使用Moq模拟受保护的泛型方法

时间:2012-02-23 15:42:59

标签: moq

在Moq中模拟受保护的虚拟(非泛型)方法很简单:

public class MyClass
{
....
      protected virtual int MyMethod(Data data){..}
}

并嘲笑它:

myMock.Protected().Setup<int>("MyMethod", ItExpr.Is<Data>( ...

如果受保护的方法是通用的,我无法找到使用相同技术的方法,例如:

protected virtual int MyMethod<T>(T data)

除了使用包装类来覆盖该方法之外,任何想法都是如此,非常感谢。

2 个答案:

答案 0 :(得分:6)

我检查了源代码,似乎不支持使用Moq模拟受保护的泛型方法

Protected()方法创建一个类ProtectedMock<T>的实例,它使用以下方法获取您要模拟的方法:

private static MethodInfo GetMethod(string methodName, params object[] args)
{
    return typeof(T).GetMethod(
           methodName,
           BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
           null,
           ToArgTypes(args),
           null);
}

它使用Type.GetMethod来获取模拟方法,但是GetMethod(尽管MSDN状态不同)与泛型不匹配,请参阅:

GetMethod for generic method

Get a generic method without using GetMethods

旁注: 在我看来,嘲笑一个受保护的成员是一种代码味道,我宁愿尝试通过重构我的设计来避免它(除了它在Moq中不支持)。

答案 1 :(得分:0)

自Moq 4.13(2019-09-01)起可以通过对受保护方法使用As和对泛型类型参数使用It.IsAnyType来完成:

classUnderTest.Protected().As<IMyMethodMock>().Setup(x => x.MyMethod(It.IsAny<It.IsAnyType>())).Returns(...);

并为模拟方法创建以下接口:

public interface IMyMethodMock
{
    int MyMethod<T>(T data);
}

完整示例:

[TestClass]
public class MockingProtectedGenericFixture
{
    [TestMethod]
    public void test()
    {
        // Arrange
        var classUnderTest = new Mock<MyClass>();
        classUnderTest.Protected().As<IMyMethodMock>().Setup(x => x.MyMethod(It.IsAny<It.IsAnyType>())).Returns(2);

        // Act
        var resForStringData = classUnderTest.Object.GetNumber("DataString");
        var resForBooleanData = classUnderTest.Object.GetNumber(true);

        // Assert
        Assert.AreEqual(2, resForStringData);
        Assert.AreEqual(2, resForBooleanData);
    }
}

public class MyClass
{
    public int GetNumber<T>(T data)
    {
        return MyMethod(data);
    }

    protected virtual int MyMethod<T>(T data)
    {
        return 1;
    }
}

public interface IMyMethodMock
{
    int MyMethod<T>(T data);
}