3

Motivation: I find myself often writing code like this...

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

That is, I often just want to make sure that a given method was NEVER called with any parameter combination.

Writing out all these It.IsAny() constants is a bit of a pain and I'd like to avoid it. My idea was to use reflection to automate this common use-case. Here's my first attempt at a method which would do this for me:

    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() });
    }

Assuming I had an interface public interface IFoo { string MyFoo(int); }, I would then call this method with VerifyNeverCalledWithAnyParameters(mockFoo, "MyFoo");.

Although it compiles, it doesn't seem to "work". That is, the verification succeeds even if I call the method on the mock object before I do the verification.

I'm unsure how to proceed solving this. Can anybody see a problem in my reflection code?

I'm aware of many other questions on SO that talk about verifying that methods were called in various exotic scenarios, but I'm yet to find any solution that does it in a generic way like I'm hoping to do here for this common use case.

sammy34
  • 5,312
  • 5
  • 29
  • 42
  • Are you willing to use [strict mocks](https://github.com/Moq/moq4/wiki/Quickstart#customizing-mock-behavior)? Any call into a method on a strict mock that was not setup (via `Setup()`) will fail the test. – Patrick Quirk Nov 09 '15 at 13:13
  • Sigh...so much time wasted on this reflection code, when such a simple solution exists :(. Thanks for the tip...it sounds like it will solve this problem and also be a good improvement to the general quality of my tests. Feel free to post it as an answer and I'll accept it... – sammy34 Nov 09 '15 at 13:32

1 Answers1

1

If you're willing to use strict mocks, you can get this behavior for free. Any call into a method on a strict mock that was not setup (via Setup()) will fail the test.

Note that there are trade-offs between loose and strict mocks. Benefits of loose mocks is reduced test setup and less brittle tests. Benefits of strict mocks include more precise testing of your system under test and its dependencies at the expense of more test setup.

In your case, if you're willing to live the increased test setup then they can provide exactly the behavior you're looking for.

Community
  • 1
  • 1
Patrick Quirk
  • 23,334
  • 2
  • 57
  • 88