无论泛型类型如何,我都可以设置一个 return 的模拟吗?

Can I set-up a mock to return regardless of generic type?

我尝试用单元测试测试的代码执行以下操作:

void DoSomething()
{
   var myTypeImplementation = _lifetimeScope.Resolve<IMyInterface<MyType>>();
   var mySecondTypeImplementation = _lifetimeScope.Resolve<IMyInterface<MySecondType>>();

   myTypeImplementation.Bar();
   mySecondTypeImplementation.Bar();
}

问题

如何通过隐式处理通用类型来模拟 _lifetimeScope (ILifetimeScope)?

我尝试过的

我有以下内容并且可以正常工作,但是除了我在示例中使用的 2 种类型之外,还有更多类型,所以有一个 lot of copy/paste:

        var mockFirstType = Substitute.For<IMyInterface<MyType>>();
        _mockLifetimeScope.Resolve<IMyInterface<MyType>().Returns(mockFirstType);

        
        var mockSecondType = Substitute.For<IMyInterface<MySecondType>>();
        _mockLifetimeScope.Resolve<IMyInterface<MySecondType>().Returns(mockSecondType);

在这个设置之后,我仍然需要断言,所以现在我有每个类型的断言:

        mockFirstType.Received().Bar();
        mockSecondType.Received().Bar();

相反,理想的做法是将此测试编写为 Theory 并通过 Type 也许?但是一些我不显式处理类型的替代方法会更简洁。

选项 1:

[Fact]
public void TestMethod()
{
    var myFirstVerificationCallback = GetVerificationCallback<MyType>();
    var mySecondVerificationCallback = GetVerificationCallback<MySecondType>();
    var myThirdVerificationCallback = GetVerificationCallback<MyThirdType>();

    myFirstVerificationCallback();
    mySecondVerificationCallback();
    myThirdVerificationCallback();
}

private Action GetVerificationCallback<T>()
{
    var typeMock = Substitute.For<IMyInterface<T>>();
    
    _mockLifetimeScope
        .Resolve<IMyInterface<T>>()
        .Returns(typeMock);

    return () => typeMock
        .Received()
        .Bar();
}

选项 2(可能):

[Theory]
[InlineData(typeof(MyType))]
[InlineData(typeof(MySecondType))]
[InlineData(typeof(MyThirdType))]
public void TestMethod(Type typeParameterType)
{
    var serviceTypeToMock = typeof(IMyInterface<>).MakeGenericType(typeParameterType);
    var substitution = Substitute.For(new Type[] {serviceTypeToMock}, Array.Empty<object>());

    _mockLifetimeScope
        .Resolve(serviceTypeToMock)
        .Returns(substitution);

    (substitution.Received() as dynamic).Bar();
}