1

How can I tell Moq to expect multiple calls so I can still use the MockRepository to VerifyAll, as below?

[TestFixture]
public class TestClass
{
    [SetUp]
    public void SetUp()
    {
        _mockRepository = new MockRepository(MockBehavior.Strict);
        _mockThing = _mockRepository.Create<IThing>();

        _sut = new Sut(_mockThing.Object);
    }

    [TearDown]
    public void TearDown()
    {
        _mockRepository.VerifyAll();
    }

    private Mock<IThing> _mockThing;

    private MockRepository _mockRepository;

    [Test]
    public void TestManyCalls(Cell cell)
    {
       _mockThing.SetUp(x => x.DoSomething()).Return(new DoneStatus());
    }
}

I know you can do this at verify time, but then I would have to verify everything independently. Is there a to tell it what to expect, rather than verifying it after the event?

Somthing similar to:

_mockThing.SetUp(x => x.DoSomething()).Return(new DoneStatus()).Times(20);

Basically, I'd like to set all me expectations at the start of the test rather than having them in more than one place.

BanksySan
  • 27,362
  • 33
  • 117
  • 216

1 Answers1

1

Putting aside the MockRepository for the moment, I've created a class that inherits from Mock to provide the functionality you're after. Firstly, the usage (XUnit syntax):

    [Fact]
    public void SomeTest()
    {
        var mock = new Mock2<IDependency>();
        var sut = new Sut(mock.Object);
        mock.SetupAndExpect(d => d.DoSomething(It.IsAny<string>(), It.IsAny<long>()),Times.Once).Returns(3);
        mock.SetupAndExpect(d => d.DoSomethingNoReturn(It.IsAny<string>()), Times.Once);
        mock.SetupAndExpect(d => d.DoSomethingNoReturn(It.IsAny<string>()), Times.Once);
        sut.CallDoSomething();
        mock.VerifyAllExpectations();
    }

The SetupAndExpect method is a replacement for Setup that allows Times to be passed. The VerifyAllExpectations is an equivalent to VerifyAll. You could fiddle around with these names if you wanted.

The Mock2 class stores the expression and times passed to SetupAndExpect ready for later use during VerifyAllExpectations.

Before I show the Mock2 code and talk about a MockRepository solution, a word of explanation about the wordiness. It was fairly easy to get it working for mocked methods with no return value as the expressions all have a type that is generic over the mocked type. For methods with a return value, however, the underlying verification to be called is Mock.Verify<TResult>(...). In order to be able to bind to the correctly closed method during VerifyAllExpectations I ended up using reflection. I'm sure modifying Mock itself to put this functionality in would allow for a less hacky solution.

Now, back to the repository: My thoughts are to modify Mock2 so that rather than inheriting from Mock, it takes an instance of Mock as a constructor parameter and uses that to call Setup and Verify. Then you could write a new extension method on MockRepository (Create2??) that calls the original MockRepository.Create and passes the created Mock instance to the constructor of a Mock2 instance, which it then returns.

A final alternative to this is to add SetupAndExpect and VerifyAllExpectations as extension methods on Mock. However, the storage of the expectation information would then probably have to be in some static state and face clean up issues.

Here's the Mock2 code:

public class Mock2<T> : Mock<T> where T:class
{
    private readonly Dictionary<Type, List<Tuple<Expression,Func<Times>>>> _resultTypeKeyedVerifications =
        new Dictionary<Type, List<Tuple<Expression, Func<Times>>>>();

    private readonly List<Tuple<Expression<Action<T>>, Func<Times>>> _noReturnTypeVerifications = 
        new List<Tuple<Expression<Action<T>>, Func<Times>>>();

    public ISetup<T, TResult> SetupAndExpect<TResult>(Expression<Func<T, TResult>> expression, Func<Times> times)
    {
        // Store the expression for verifying in VerifyAllExpectations
        var verificationsForType = GetVerificationsForType(typeof(TResult));
        verificationsForType.Add(new Tuple<Expression, Func<Times>>(expression, times));

        // Continue with normal setup
        return Setup(expression);
    }

    public ISetup<T> SetupAndExpect(Expression<Action<T>> expression, Func<Times> times)
    {
        _noReturnTypeVerifications.Add(new Tuple<Expression<Action<T>>, Func<Times>>(expression, times));
        return Setup(expression);
    }

    private List<Tuple<Expression, Func<Times>>> GetVerificationsForType(Type type)
    {
        // Simply gets a list of verification info for a particular return type,
        // creating it and putting it in the dictionary if it doesn't exist.
        if (!_resultTypeKeyedVerifications.ContainsKey(type))
        {
            var verificationsForType = new List<Tuple<Expression, Func<Times>>>();
            _resultTypeKeyedVerifications.Add(type, verificationsForType);
        }
        return _resultTypeKeyedVerifications[type];
    }

    /// <summary>
    /// Use this instead of VerifyAll for setups perfomed using SetupAndRespect
    /// </summary>
    public void VerifyAllExpectations()
    {
        VerifyAllWithoutReturnType();
        VerifyAllWithReturnType();
    }

    private void VerifyAllWithoutReturnType()
    {
        foreach (var noReturnTypeVerification in _noReturnTypeVerifications)
        {
            var expression = noReturnTypeVerification.Item1;
            var times = noReturnTypeVerification.Item2;
            Verify(expression, times);
        }
    }

    private void VerifyAllWithReturnType()
    {
        foreach (var typeAndVerifications in _resultTypeKeyedVerifications)
        {
            var returnType = typeAndVerifications.Key;
            var verifications = typeAndVerifications.Value;

            foreach (var verification in verifications)
            {
                var expression = verification.Item1;
                var times = verification.Item2;

                // Use reflection to find the Verify method that takes an Expression of Func of T, TResult
                var verifyFuncMethod = GetType()
                    .GetMethods(BindingFlags.Instance | BindingFlags.Public)
                    .Single(IsVerifyMethodForReturnTypeAndFuncOfTimes)
                    .MakeGenericMethod(returnType);

                // Equivalent to Verify(expression, times)
                verifyFuncMethod.Invoke(this, new object[] {expression, times});
            }
        }
    }

    private static bool IsVerifyMethodForReturnTypeAndFuncOfTimes(MethodInfo m)
    {
        if (m.Name != "Verify") return false;
        // Look for the single overload with two funcs, which is the one we want
        // as we're looking at verifications for functions, not actions, and the
        // overload we're looking for takes a Func<Times> as the second parameter
        var parameters = m.GetParameters();
        return parameters.Length == 2
               && parameters[0] // expression
                   .ParameterType // Expression
                   .GenericTypeArguments[0] // Func
                   .Name == "Func`2"
               && parameters[1] // times
                   .ParameterType // Func
                   .Name == "Func`1";
    }
}

Final warnings: This is only lightly tested and not tested concurrently. It doesn't have an equivalent to the overload of Verify that takes Times rather than Func<Times>. There are probably some better names for the methods and/or reasons why this is all generally a bad idea in the first place.

I hope it's of some use to you or someone!

Josh Gallagher
  • 5,211
  • 2
  • 33
  • 60