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

发布于 2025-01-08 16:51:07 字数 411 浏览 0 评论 0原文

在 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)

除了使用之外,任何想法如何做到这一点高度赞赏覆盖该方法的包装类。

To mock a protected virtual (non-generic) method in Moq is easy:

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

And to mock it:

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

I could not find a way to use the same technique if the protected method is generic, like:

protected virtual int MyMethod<T>(T data)

Any idea how to do it, besides using a wrapper class to override that method, is highly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

原谅我要高飞 2025-01-15 16:51:07

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

Protected() 方法创建类 ProtectedMock的实例; 它使用以下方法来获取您要模拟的方法:

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

获取通用方法而不使用 GetMethods

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

I've checked the source and it seems mocking protected generic methods with Moq is not supported:

The Protected() method creates an instance of a class ProtectedMock<T> which uses the following method to get the method that you want to mock:

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

It uses Type.GetMethod to get the method for mocking, but GetMethod (although MSDN states differently) don't play nice with generics, see:

GetMethod for generic method

Get a generic method without using GetMethods

Side note:
In my opinion mocking a protected member is a code smell, and I would rather try to avoid it anyway with refactoring my design (beside that it's not supported in Moq).

像极了他 2025-01-15 16:51:07

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

classUnderTest.Protected( ).As().Setup(x =>; x.MyMethod(It.IsAny())).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);
}

It can be done since Moq 4.13 (2019-09-01) by using As for protected methods and It.IsAnyType for generic type arguments:

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

And create the following interface for the mocking method:

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

Full example:

[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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文