如何在 Mock 转换为对象后获取 Mock 的原始类型

问题描述 投票:0回答:1

我有一个

ServiceCollection
,我想创建一个可以传入一组参数的方法,并让
ServiceCollection
在请求匹配类型时返回这些服务。我正在使用 Autofixture 创建我的服务。当我调用
fixture.Create<IMyService>
时,它会返回
Mock<IMyService>
。例如

public static IServiceProvider CreateServiceProvider(params object[] services)
{
    var serviceCollection = new ServiceCollection();
    
    foreach (object service in services)
    {
       serviceCollection.AddTransient(factory => service);
    }

    return serviceCollection.BuildServiceProvider();
}

然后我想这样使用它

[Fact]
public void TestSomething()
{
   // This causes myFirstService to be of type of type IMyFirstService,
   // but have a value of type Mock<IMyFirstService> (same for
   // mySecondService)
   var fixture = new Fixture();
   IMyFirstService myFirstService = fixture.Create<IMyFirstService>();
   IMySecondService mySecondService = fixture.Create<IMySecondService>();

   var serviceProvider = CreateServiceProvider(myFirstService, mySecondService);

   // I want the returned objects to be myFirstService and mySecondService
   // that I created above
   var resolvedFirstService = serviceProvider.GetService<IMyFirstService>();
   var resolvedSecondService = serviceProvider.GetService<IMySecondService>();
}

问题是

myFirstService
mySecondService
不会返回,因为当调用
object
时,服务会被强制转换为
CreateServiceProvider
,因此它们会在
ServiceCollection
中注册为
object
类型,而不是正确的接口类型。我尝试使用
serviceProvider.GetService(service.GetType(), factory => service)
但问题是
service.GetType()
返回
Castle.Proxies.IMyFirstServiceProxy

我知道我可以通过执行下面的代码来完成这项工作,但我希望它通过让

CreateServiceProvider
方法注册这些服务来工作。

[Fact]
public void TestSomething()
{
   var fixture = new Fixture();
   IMyFirstService myFirstService = fixture.Create<IMyFirstService>();
   IMySecondService mySecondService = fixture.Create<IMySecondService>();

   var serviceCollection = new ServiceCollection();
   serviceCollection.AddTransient(factory => myFirstService);
   serviceCollection.AddTransient(factory => mySecondService);
   var serviceProvider = serviceCollection.BuildServiceProvider();

   var resolvedFirstService = serviceProvider.GetService<IMyFirstService>();
   var resolvedSecondService = serviceProvider.GetService<IMySecondService>();
}
c# asp.net dependency-injection moq autofixture
1个回答
0
投票

我不知道实现这一目标的简单方法,但如果你坚持走这条路,你可以采用相当脆弱的反射路径并弄乱实现细节:

static IServiceProvider CreateServiceProvider(params object[] services)
{
    var serviceCollection = new ServiceCollection();

    foreach (object service in services)
    {
        var m = service as IMocked;
        var value = typeof(Mock).GetProperty("MockedType", BindingFlags.Instance | BindingFlags.NonPublic)
            .GetValue(m.Mock) as Type;
        serviceCollection.AddTransient(value, _ => service);
    }

    return serviceCollection.BuildServiceProvider();
}

但这可能非常脆弱,所以我建议重新考虑该方法并使用

Type
作为参数:

static IServiceProvider CreateServiceProvider(params Type[] services)
{
    var serviceCollection = new ServiceCollection();
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var context = new SpecimenContext(fixture);
    foreach (var serviceType in services)
    {
        var o1 = fixture.Create(serviceType, context);
        serviceCollection.AddTransient(serviceType, _ => o1);
    }

    return serviceCollection.BuildServiceProvider();
}

通过这样的电话:

var serviceProvider = CreateServiceProvider(typeof(IMyFirstService), typeof(IMySecondService));
© www.soinside.com 2019 - 2024. All rights reserved.