2015-11-08 71 views
2

动机:我发现自己经常写这样的代码......用于模拟(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() }); 
    } 

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

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

我不确定如何解决这个问题。任何人都可以在我的反射代码中看到问题吗?

我所知道的对,这样讲验证方法被称为各种异国情调的场景很多其他的问题,但我还没有找到,做它在一个通用的方式就像我希望做任何解决方案这里为这个常见的用例。

+0

你愿意用[严格模拟考试(https://github.com/Moq/moq4/wiki/Quickstart#customizing-mock-behavior)?任何未经设置的严格模拟(通过'Setup()')调用方法都将使测试失败。 –

+0

叹息......在这样的反射代码上浪费了很多时间,当这样一个简单的解决方案存在:(。谢谢你的提示......这听起来像它会解决这个问题,也是一个很好的改善,我的一般质量测试,随意发布它作为答案,我会接受它... – sammy34

回答

1

如果你愿意使用strict mocks,你可以得到这个行为是免费的。任何未经设置的严格模拟调用方法(通过Setup())都将使测试失败。

注意there are trade-offs between loose and strict mocks。松散模拟的好处是减少了测试设置并减少了脆性测试。严格模拟的好处包括更精确地测试您的被测系统及其依赖性,代价是更多的测试设置。

在你的情况,如果你愿意住在增加测试设置那么他们可以准确地提供你正在寻找的行为。

相关问题