Skip to content

About

A library for ensuring that mock methods are called in correct order while strictly separating the act & assertion phase

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

87 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Moq.Contrib.InOrder

Nuget

For docs & instructions on the latest stable release, switch to main branch please

Moq.Contrib.InOrder is a library for ensuring that mock methods are called in correct order while strictly separating the acting & verification phase.

Register all mock setups that should be taken into account when verifying the call order in a var queue = CallQueue.Create(x => { /* here */});. To mark a mock method as relevant for order verification, use .SetupInOrder(...) instead of the normal .Setup(...) provided by moq (for every of moq's Setup methods, there is an InOrder version, e.g. SetupGetInOrder, SetupAddInOrder, etc). Verify the call order after executing your test method by queue.VerifyOrder().

Examples

// Arrange
var mock = new Mock<IDummy>();
var sut = new TestedDummyClass(mock.Object);

var queue = CallQueue.Create(x0 =>
{
    mock.SetupInOrder(x => x.ExecuteAction("a"), x0);
    mock.SetupInOrder(x => x.ExecuteAction("b"), x0);
});

// Act
sut.TestedDummyMethod();

// Assert
queue.VerifyOrder();

/*
    The only call order that will satisfy queue.VerifyOrder():
    - ExecuteAction("a")
    - ExecuteAction("b")
*/

To define a loop for multiple setups, use .RegisterLoop(...). To define a loop for a single setup, use the times property of ever .SetupInOrder(...) method.

// Arrange
var mock = new Mock<IDummy>();
var sut = new TestedDummyClass(mock.Object);

var queue = CallQueue.Create(x0 =>
{
    mock.SetupInOrder(x => x.ExecuteAction("a"), x0);
    mock.SetupInOrder(x => x.ExecuteAction("b"), Times.Exactly(3), x0);

    q.RegisterLoop(x1 =>
    {
        // these two methods should be called in a loop which is expected to execute twice
        mock.SetupInOrder(x => x.ExecuteAction("c"), x1);
        mock.SetupInOrder(x => x.ExecuteAction("d"), x1);
    }, Times.Exactly(2));
});

// Act
sut.TestedDummyMethod();

// Assert
queue.VerifyOrder();

/*
    The only call order that will satisfy queue.VerifyOrder():
    - ExecuteAction("a")
    - ExecuteAction("b")
    - ExecuteAction("b")
    - ExecuteAction("b")
    - ExecuteAction("c")
    - ExecuteAction("d")
    - ExecuteAction("c")
    - ExecuteAction("d")
*/

You can also stack loop inside of loops.

var queue = CallQueue.Create(q =>
{
    q.RegisterLoop(loop =>
    {
        mock.SetupInOrder(x => x.ExecuteAction("c"), loop);
        mock.SetupInOrder(x => x.ExecuteAction("d"), loop);

        loop.RegisterLoop(loop2 =>
        {
            mock.SetupInOrder(x => x.ExecuteAction("e"), loop2);
            mock.SetupInOrder(x => x.ExecuteAction("f"), loop2);
        }, Times.AtLeast(2));
    }, Times.AtMost(2));
});

Other Invocations

For everyone using loose mocks, it's possible to make sure that no other invocations were performed on the mock via the PreventAllOtherInvocationsOf method

var mock = new Mock<IDummy>(MockBehavior.Loose);
var queue = CallQueue
    .Create(q =>
    {
        mock.SetupInOrder(x => x.ExecuteAction("a"), q);
    })
    .PreventAllOtherInvocationsOf(mock);

mock.Object.ExecuteAction("a");
mock.Object.ExecuteAction("b");

queue.VerifyOrder(); // will throw due to 'ExecuteAction("b")' call

Logging

Optionally, you can pass an ILogger<CallQueue> into CallQueue.Create that will log the expected and received calls.

var mock = new Mock<IDummy>();
var queue = CallQueue.Create(x0 =>
    {
        mock.SetupInOrder(x => x.ExecuteAction("a"), x0);
        mock.SetupInOrder(x => x.ExecuteAction("b"), Times.AtLeast(2), x0);

        x0.RegisterLoop(x1 =>
        {
            mock.SetupInOrder(x => x.ExecuteAction("c"), x1);
            mock.SetupInOrder(x => x.ExecuteAction("d"), x1);
        }, Times.Exactly(2));
    },
    _logger);

mock.Object.ExecuteAction("a");
mock.Object.ExecuteAction("b");
mock.Object.ExecuteAction("b");

mock.Object.ExecuteAction("c");
mock.Object.ExecuteAction("d");

mock.Object.ExecuteAction("c");
mock.Object.ExecuteAction("d");

Producing the following output:

Information [0]: Expected Calls:
Information [0]: 	x => x.ExecuteAction("a")
Information [0]: 	(>2 times) x => x.ExecuteAction("b")
Information [0]: 	Loop: (2 times) 
Information [0]: 		x => x.ExecuteAction("c")
Information [0]: 		x => x.ExecuteAction("d")
Information [0]: ----------------------------
Information [0]: Received Calls:
Information [0]: 	x => x.ExecuteAction("a")
Information [0]: 	x => x.ExecuteAction("b")
Information [0]: 	x => x.ExecuteAction("b")
Information [0]: 	x => x.ExecuteAction("c")
Information [0]: 	x => x.ExecuteAction("d")
Information [0]: 	x => x.ExecuteAction("c")
Information [0]: 	x => x.ExecuteAction("d")

About

A library for ensuring that mock methods are called in correct order while strictly separating the act & assertion phase

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages