-1

I have to write the test case to verify the sequence of execution of chained methods. suppose I have written code as shown below

 _store 
     .SetInput(input1)
     .Method1()
     .Method2()
     .Method3();

How can I write a test case to check SetInput executed first, method1 executed second, and so on? If someone changes the actual implementation or order of method chaining then the test case should fail. I know that I can't mock the extension method then what is the best way to write the test case to check the sequence of execution of methods.

Pavan Ambhure
  • 49
  • 1
  • 5

1 Answers1

0

Let's suppose that your _store implements the following interface:

public interface IStore
{
    IStore SetInput(string input);
    IStore Method1();
    IStore Method2();
    IStore Method3();
}

For the sake of simplicity here is class that makes use of an IStore implementation:

public class SystemUnderTest
{
    private readonly IStore _store;
    public SystemUnderTest(IStore store)
    {
        _store = store;
    }

    public void MyAction()
    {
        _store
            .SetInput("input1")
            .Method1()
            .Method2()
            .Method3();
    }
}

So, in order to make sure that the actions are executing in this particular order we can make use of the MockSequence (ref). Here is a sample unit test for this:

[Fact]
public void GivenAFlawlessStore_WhenICallMyAction_ThenItCallsTheMethodsOfTheStoreInAParticularOrder()
{
    //Arrange
    var storeMock = new Mock<IStore>();
    var expectedSequence = new MockSequence();
    storeMock.InSequence(expectedSequence).Setup(x => x.SetInput(It.IsAny<string>()))
        .Returns(storeMock.Object);
    storeMock.InSequence(expectedSequence).Setup(x => x.Method1())
        .Returns(storeMock.Object);
    storeMock.InSequence(expectedSequence).Setup(x => x.Method2())
        .Returns(storeMock.Object);
    storeMock.InSequence(expectedSequence).Setup(x => x.Method3())
        .Returns(storeMock.Object);

    var SUT = new SystemUnderTest(storeMock.Object);

    //Act 
    SUT.MyAction();

    //Assert
    storeMock.Verify(store => store.SetInput("input1"), Times.Once);
}

If you change the order either in the unit test or inside the MyAction method it will fail with a NullReferenceException, because it can't call the next method on a null.

Change the order inside the MyAction

public void MyAction()
{
    _store
        .SetInput("input1")
        .Method2()
        .Method1() //NullReferenceException
        .Method3();
}

Change the order of the MockSequence

//Arrange
var storeMock = new Mock<IStore>();
var expectedSequence = new MockSequence();
storeMock.InSequence(expectedSequence).Setup(x => x.SetInput(It.IsAny<string>()))
    .Returns(storeMock.Object);
storeMock.InSequence(expectedSequence).Setup(x => x.Method1())
    .Returns(storeMock.Object);
storeMock.InSequence(expectedSequence).Setup(x => x.Method3())
    .Returns(storeMock.Object);
storeMock.InSequence(expectedSequence).Setup(x => x.Method2())
.Returns(storeMock.Object);

In order words your Setup calls won't have any effect in advance. When you call the SetInput from the MyAction the first setup will be executed in the sequence. If you try to call Method2 before Method1's Setup call then it will fail.

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
  • This works only if methods are in the interface but in my case SetInput("input1"),Method1(), Method2(), Method3() are extension methods and i can't write this in the setup like this Setup(x => x.Method1()) – Pavan Ambhure Nov 05 '20 at 08:16
  • @PavanAmbhure You can't directly mock extension methods because they are `static`. [Related SO topic](https://stackoverflow.com/questions/2295960/mocking-extension-methods-with-moq) – Peter Csala Nov 05 '20 at 08:29