asp.net 我怎样才能得到原始类型的一个模拟后,模拟已被强制转换为一个对象

gmxoilav  于 2023-10-21  发布在  .NET
关注(0)|答案(1)|浏览(116)

我有一个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>();
}

问题是myFirstServicemySecondService没有返回,因为当调用CreateServiceProvider时,服务被转换为object,所以它们在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>();
}
vuktfyat

vuktfyat1#

我不知道一个简单的方法来实现这一点,但如果你坚持这样做,你可以选择相当脆弱的反射路径,并扰乱实现细节:

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

    foreach (object service in services)
    {
        // relying on the mocked object implementing IMocked:
        var mocked = service as IMocked; 

        // using internal property:
        var mockedType = typeof(Mock).GetProperty("MockedType", BindingFlags.Instance | BindingFlags.NonPublic)
            .GetValue(mocked.Mock) as Type;

        serviceCollection.AddTransient(mockedType, _ => 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 instance = fixture.Create(serviceType, context);
        serviceCollection.AddTransient(serviceType, _ => instance);
    }

    return serviceCollection.BuildServiceProvider();
}

打电话像:

var serviceProvider = CreateServiceProvider(typeof(IMyFirstService), typeof(IMySecondService));

相关问题