Skip to content

Ordered Assertions

The concept of ordered assertions is somewhat complex and nothing that should be used frequently but there are times when it's really needed.

In FakeItEasy you can assert that calls happened in a specific order on more than one fake object.

Note that this feature is not available in the 1.0.x versions.

Details

One area where ordered asserts are useful is when you need to test that a call to a fake has happened between two other calls creating a scope. This could be useful when dealing with transactions or units of work.

public interface IUnitOfWorkFactory
{
    IDisposable BeginWork();
}

public interface IDoSomethingPrettyUseful
{
    void JustDoIt();
}

public class Worker
{
    private IUnitOfWorkFactory unitOfWorkFactory;
    private IDoSomethingPrettyUseful usefulCollaborator;

    public Worker(IUnitOfWorkFactory unitOfWorkFactory, IDoSomethingPrettyUseful usefulCollaborator)
    {
        this.unitOfWorkFactory = unitOfWorkFactory;
        this.usefulCollaborator = usefulCollaborator;
    }

    public void JustDoIt()
    {
        using (this.unitOfWorkFactory.BeginWork())
        {
            this.usefulCollaborator.JustDoIt();
        }
    }
}

In the following example we'll assert that the call to usefulCollaborator.JustDoIt() happened between the calls to BeginWork and the Dispose method of the returned unit of work.

[Test]
public void Should_start_work_within_unit_of_work()
{
    // Arrange
    var unitOfWork = A.Fake<IDisposable>();

    var unitOfWorkFactory = A.Fake<IUnitOfWorkFactory>();
    A.CallTo(() => unitOfWorkFactory.BeginWork()).Returns(unitOfWork);

    var usefulCollaborator = A.Fake<IDoSomethingPrettyUseful>();

    var worker = new Worker(unitOfWorkFactory, usefulCollaborator);

    using (var scope = Fake.CreateScope())
    {
        // Act
        worker.JustDoIt();

        // Assert
        using (scope.OrderedAssertions())
        {
            A.CallTo(() => unitOfWorkFactory.BeginWork()).MustHaveHappened();
            A.CallTo(() => usefulCollaborator.JustDoIt()).MustHaveHappened();
            A.CallTo(() => unitOfWork.Dispose()).MustHaveHappened();
        }
    }
}

In the test we need to create a "fake scope" that wraps the call to the tested class and the assertions. A fake scope is used to catch all the calls to any fake object within that scope (among other things).

Then to do the assertions we call the OrderedAssertions method on the scope, any assertion within this using statement will now need to have happened in the same order as the assertions are specified or the test will fail.

With the current implementation of Worker, the test will pass. But let's change the order of the calls in JustDoIt:

public void JustDoIt()
{ 
    using (this.unitOfWorkFactory.BeginWork())
    { 

    }
    this.usefulCollaborator.JustDoIt();
}

The test will now fail with the following exception message:

 Assertion failed for the following calls:
    'OrderedAssertsDemo.IUnitOfWorkFactory.BeginWork()' repeated once
    'OrderedAssertsDemo.IDoSomethingPrettyUseful.JustDoIt()' repeated once
    'System.IDisposable.Dispose()' repeated once
  The calls where found but not in the correct order among the calls:
    1.  'OrderedAssertsDemo.IUnitOfWorkFactory.BeginWork()'
    2.  'System.IDisposable.Dispose()'
    3.  'OrderedAssertsDemo.IDoSomethingPrettyUseful.JustDoIt()'