Sergey Sergey - 2 months ago 12
ASP.NET (C#) Question

Moq SetupSequence doesn't work

I try to use the

SetupSequence
method of the Moq 4.5 framework.

Class that should be mocked:

public class OutputManager {
public virtual string WriteMessage(string message) {
// write a message
}
}


Mock:

var outputManagerMock = new Mock<OutputManager>();
var writeMessageCalls = 0;
var currentMessage = String.Empty;

outputManagerMock.Setup(o => o.WriteMessage(It.IsAny<string>())).Callback((string m) => {
writeMessageCalls++;
message = m;
});


This code works fine. But I'd like having a different setup for each call of the
WriteMessage
method. Well, I use
SetupSequence
instead of
Setup
:

var outputManagerMock = new Mock<OutputManager>();
var writeMessageCalls = 0;
var firstMessage = String.Empty;
var secondMessage = String.Empty;

outputManagerMock.SetupSequence(o => o.WriteMessage(It.IsAny<string>()))
.Callback((string m) => {
writeMessageCalls++;
firstMessage = m;
}).Callback((string m) => {
writeMessageCalls++;
secondMessage = m;
});


Then I've got the error:


Error CS0411 The type arguments for method

'SequenceExtensions.SetupSequence<TMock, TResult>(Mock<TMock>,
Expression<Func<TMock, TResult>>)'
cannot be inferred from the usage.

Try specifying the type arguments explicitly.


I've found the possible solution here - SetupSequence in Moq. But it looks like a workaround.

Answer

If OutputManager is a dependency for other classes then you should consider abstracting that class to make it easier to mock for your tests.

public interface IOutputManager {
    string WriteMessage(string message);
}

That would then mean that the implementation of this interface would look like what you had originally with the addition of the interface.

public class OutputManager : IOutputManager {
    public string WriteMessage(string message) {
        // write a message
    }
}

Given that you originally attempted to mock OutputManager then the assumption here is that it is not the system under test as you typically do not mock the target of the test but rather its dependencies.

So let's assume a dependent class looked something like this.

public class DependentOnIOutputManager {
    private IOutputManager outputManager;

    public DependentOnIOutputManager(IOutputManager outputManager) {
        this.outputManager = outputManager;
    }

    public string SomeMethod(string message) {        
        // write a message
        var output = outputManager.WriteMessage(message);
        //...other code
        return output;
    }
}

Then an example test could look like this.

[TestMethod]
public void Moq_SetupSequence_Example() {
    //Arrange
    var mock = new Mock<IOutputManager>();

    mock.SetupSequence(x => x.WriteMessage(It.IsAny<string>()))
        .Returns("first")
        .Returns("second")
        .Throws<InvalidOperationException>();

    var outputManager = mock.Object;

    var sut = new DependentOnIOutputManager(outputManager);

    //Act
    var first = sut.SomeMethod("1st");

    var second = sut.SomeMethod("2nd");

    Exception e = null;
    try {
        sut.SomeMethod("3rd");
    } catch (InvalidOperationException ex) {
        e = ex;
    }

    //Assert
    Assert.IsNotNull(first);
    Assert.IsNotNull(second);
    Assert.IsNotNull(e);
}