c# - Mock 的通用方法(Moq 库)验证从未使用任何参数组合调用方法

标签 c# unit-testing generics mocking moq

动机:我发现自己经常写这样的代码......

myMock.Verify(m => m.SomeMethod(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>(), ..., It.IsAny<int>()), Times.Never());

也就是说,我通常只想确保从未使用任何参数组合调用给定方法。

写出所有这些 It.IsAny() 常量有点麻烦,我想避免它。我的想法是使用反射来自动化这个常见的用例。这是我第一次尝试可以为我做这件事的方法:

    public void VerifyNeverCalledWithAnyParameters<T>(Mock<T> mock, string methodName) where T : class
    {
        // Get the info for the method in which we're interested
        var methodInfo = typeof(T).GetMethod(methodName);
        // Get the parameter info for that method
        var parameters = methodInfo.GetParameters();
        // Build up a list of parameter expressions. Each one will be an It.IsAny<K>() constant, where K is the type of the respective parameter
        var parameterExpressions = new List<Expression>();
        foreach (var parameterInfo in parameters)
        {
            var parameterType = parameterInfo.ParameterType;
            var itIsAnyObject = typeof(It).GetMethod("IsAny").MakeGenericMethod(parameterType).Invoke(null, null);
            parameterExpressions.Add(Expression.Constant(itIsAnyObject));
        }

        // Build up the lambda which represents "m => m.MethodName(It.IsAny<K1>(), It.IsAny<K2>(),...)"
        var delegateType = typeof(Action<IFoo>);
        var parameter = Expression.Parameter(typeof(IFoo), "f");
        var yourExpression = Expression.Lambda(delegateType, Expression.Call(parameter, methodInfo, parameterExpressions), parameter);

        // Verify the method call by invoking the verify method on the mock with our expression and asserting Times.Never() to ensure it was never called with any parameters
        mock.GetType().GetMethod("Verify", new[] { yourExpression.GetType(), typeof(Times) }).Invoke(mock, new object[] { yourExpression, Times.Never() });
    }

假设我有一个接口(interface) public interface IFoo { string MyFoo(int); },然后我将使用 VerifyNeverCalledWithAnyParameters(mockFoo, "MyFoo"); 调用此方法。

虽然它可以编译,但它似乎没有“工作”。也就是说,即使我在验证之前调用模拟对象上的方法,验证也会成功。

我不确定如何继续解决这个问题。有人能看出我的反射代码有问题吗?

我知道关于 SO 的许多其他问题都在谈论验证方法是否在各种奇特的场景中被调用,但我还没有找到任何以通用方式执行此操作的解决方案,就像我希望在这里做的那样对于这个常见用例。

最佳答案

如果您愿意使用 strict mocks ,您可以免费获得此行为。对未设置(通过 Setup())的严格模拟的方法的任何调用都将无法通过测试。

请注意 there are trade-offs between loose and strict mocks .松散模拟的好处是减少测试设置和减少测试的脆弱性。严格模拟的好处包括以更多的测试设置为代价对被测系统及其依赖项进行更精确的测试。

在您的情况下,如果您愿意接受增加的测试设置,那么他们可以提供您正在寻找的行为。

关于c# - Mock 的通用方法(Moq 库)验证从未使用任何参数组合调用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33593020/

相关文章:

c# - 具有私有(private) setter 的 UWP DependencyProperty

asp.net-mvc - 如何在 ASP.NET MVC 中对 ActionFilter 进行单元测试?

delphi - 为什么释放不为空的TList <Int64>不会导致内存泄漏?

C++ 泛型列表赋值

c# - ASP .NET C# SQL 在 ExecuteScalar 上返回 DBNULL

c# - 如何在 XAML 中公开控件以便在其他类中看到

c# - 使用 Directory.Getfiles 指定绝对路径

python - 如何测试 Python 函数是否引发异常?

spring - 测试 Spring 端点时如何防止 NestedServletException?

Java 将特定类的列表添加到 java.lang.Object 的列表与 java 8 流一起工作 - 为什么?