vivek86
vivek86

Reputation: 753

Moq Setup override

I have gone through all the previous answers and none of them solve my problem.

lets say that i have the following code:

public interface ISomeInterface
{
    int SomeMethod(int a, string b);
}

Now i have a common mocking class that defines some default behaviour for the above method

public class CommonMock
{
    public Mock<ISomeInterface> MockInterface = new Mock<ISomeInterface>().Setup(x => x.SomeMethod(It.IsAny<int>(), It.IsAny<string>())).Returns(It.IsAny<int>());
}

I need some default behaviour because I have a whole lot of test cases which need a default behaviour.

But in some specific test scenarios, in a totally separate test class, i need to be able to return a different value as i am testing some specific test case.

Something like below:

[Test]
public void TestSomeMethodSpecific()
{
    var commonMock = new CommonMock();
    commonMock.MockInterface.Setup(x => x.SomeMethod(It.IsAny<int>(), It.IsAny<string>())).Returns(42);

    // Do some test based on the new return value
}

How can I achieve that?

Below i am attaching a bit of the actual code:

Common Setup

public class MockStore
{
    public Mock<IProcessHandler> ProcessHandler = new Mock<IProcessHandler>();
    ProcessHandler.Setup(x => x.GetCurrentProcessRunId()).Returns(It.IsAny<int>());
}

Overridden Setup in a test class

var mockstore = new MockStore();
mockStore.ProcessHandler.Setup(x => x.GetCurrentProcessRunId()).Returns(25);

And there are almost 50 to 70 such mocks each of which return from simple types to complex classes.

Upvotes: 13

Views: 13086

Answers (2)

Levi
Levi

Reputation: 371

You could have global mock objects that you modify as you go. For instance I have this:

[TestClass]
public class StoreServiceTest
{
    Mock<IAccess> mockAccess;
    Mock<IAccess> mockAccessNoData;
    Mock<IDataReader> mockReader;
    Mock<IDataReader> mockReaderNoData;
    Mock<IStoreService> mockStoreService;

And then on the TestInitiailize, I Setup the default implementation as follows:

mockReader = new Mock<IDataReader>();
mockReader.Setup(m => m.IsDBNull(It.IsAny<int>())).Returns(false);
mockReader.Setup(m => m.GetString(It.IsAny<int>())).Returns("stub");
mockReader.Setup(m => m.GetBoolean(It.IsAny<int>())).Returns(true);
mockReader.Setup(m => m.GetInt32(It.IsAny<int>())).Returns(32);
mockReader.SetupSequence(m => m.Read()).Returns(true).Returns(false); // setup sequence to avoid infinite loop

mockAccess = new Mock<IAccess>();
mockAccess.Setup(m => m.ReadData(It.IsAny<string>(), It.IsAny<object[]>())).Returns(mockReader.Object);

mockReaderNoData = new Mock<IDataReader>();
mockReaderNoData.Setup(m => m.Read()).Returns(false);

mockAccessNoData = new Mock<IAccess>();
mockAccessNoData.Setup(m => m.ReadData(It.IsAny<string>(), It.IsAny<object[]>())).Returns(mockReaderNoData.Object);

mockStoreService = new Mock<IStoreService>(); 

And now for a default kind of test, all I do is pass the mockReader.Object which should have the default implementation since every test begins with TestInitialize, and then for a special case, say I want to return "sub" instead of "stub" for IDataReader's GetString() method, I can do something like this:

mockReader.Setup(m => m.GetString(It.IsAny<int>())).Returns((int col) => {
    if (col == 2) return "sub";
    else return "stub";
});

Hope that helps!

Upvotes: 2

Owen Pauling
Owen Pauling

Reputation: 11841

That should work? If you create a subsequent setup on a method and it's non-conditional (no constraints on the arguments) then it removes all previous setups for the method.

You can see my answer here that explains it with the source code.

If you want multiple Setups that are conditional, to return different values based on the arguments, then see How to setup a method twice for different parameters with mock.

Without seeing your full code, perhaps you are already using conditional Setups. In which case the order is important and perhaps you are overriding an earlier Setup with a more general one.

Upvotes: 5

Related Questions