Archive for July 2010

Moq Sequences

I have recently started to use Moq for mocking and I really like it. The fluent interface and Lambda support makes it very easy and natural to use.

However, I quickly ran into a situation where I wanted to ensure that methods on a mock object were called in a particular order. I have provided a simpler example below where I want to check that BlogPresenter.Show() shows blogs in reverse chronological order:

public class Post
{
    public DateTime DateTime { get; set; }
}

public class BlogPresenter
{
    private readonly BlogView view;

    public BlogPresenter(BlogView view)
    {
        this.view = view;
    }

    public void Show(IEnumerable posts)
    {
        foreach (var post in posts.OrderByDescending(post => post.DateTime))
            view.ShowPost(post);
    }
}

public interface BlogView
{
    void ShowPost(Post post);
}

To check this I used a callback to increment a counter like this:

[Test]
public void Should_show_each_post_once_with_most_recent_first()
{
    var olderPost = new Post { DateTime = new DateTime(2010, 1, 1) };
    var newerPost = new Post { DateTime = new DateTime(2010, 1, 2) };
    var posts = new List { newerPost, olderPost };

    var mockView = new Mock();

    var viewOrder = 0;

    mockView.Setup(v => v.ShowPost(newerPost)).Callback(() => Assert.That(viewOrder++, Is.EqualTo(0)));
    mockView.Setup(v => v.ShowPost(olderPost)).Callback(() => Assert.That(viewOrder++, Is.EqualTo(1)));

    new BlogPresenter(mockView.Object).Show(posts);

    mockView.Verify(v => v.ShowPost(newerPost), Times.Once());
    mockView.Verify(v => v.ShowPost(olderPost), Times.Once());
}

This works code but is not very intentional. I wanted to express the intent the there is a required ordering of method calls. After searching around I found a nice code snippet from Max Guernsey, III that was promising. I thought I would push a little further to see if I could get something like this:

[Test]
public void Should_show_each_post_with_most_recent_first_using_sequences()
{
    var olderPost = new Post { DateTime = new DateTime(2010, 1, 1) };
    var newerPost = new Post { DateTime = new DateTime(2010, 1, 2) };
    var posts = new List { newerPost, olderPost };

    var mockView = new Mock();

    using (Sequence.Create())
    {
        mockView.Setup(v => v.ShowPost(newerPost)).InSequence();
        mockView.Setup(v => v.ShowPost(olderPost)).InSequence();

        new BlogPresenter(mockView.Object).Show(posts);
    }
}

So, I created Moq.Sequences and you download Moq.Sequences.dll from github. Simply, add Moq.Sequences.dll as a reference in your .Net project and add a using Moq.Sequences; in your test class. Moq.Sequences supports the following:

  • checks order of method calls, property gets and property sets
  • allows you to specify the number of times a call is made before the next one is expected
  • allows intermixing of sequenced and non-sequenced expectations
  • thread safe – each thread can have its own sequence

Sequences

Sequences are added using the Sequence static class and extension methods. You create a sequence by calling:

using (Sequence.Create())
{
    ...
}

Sequences that do not fully complete are detected when the sequence is disposed. So, all the setups and mock calls should be done within the lifetime of the sequence.

Steps

Within a sequence you set the expectations for ordering via an extension method InSequence<(). I call these steps. For example,

using (Sequence.Create())
{
    mock.Setup(_ => _.Method1()).InSequence();
    mock.Setup(_ => _.Method2()).InSequence();
    ...
}

This sets an expectation that Method1() will be called once followed by a single call to Method2. You can set more sophisticated expectations by using a Times parameter:

using (Sequence.Create())
{
    mock.Setup(_ => _.Method1()).InSequence(Times.AtMostOnce());
    mock.Setup(_ => _.Method2()).InSequence(Times.Between(1, 10, Range.Inclusive));
    ...
}

Steps can be created for method calls, property gets and property sets:

using (Sequence.Create())
{
    mock.Setup(_ => _.Method1()).InSequence(); // method call
    mock.SetupGet(_ => _.Property1).InSequence().Returns(0);  // property get
    mock.SetupSet(_ => _.Property2 = 0).InSequence(); // property set
    ...
}

Also, sequenced steps can be intermingled with non-sequenced expectations.

Loops

Loops are used when you want to check that as group of method calls are called in order several times. An example of this could be some resources which you expect to be opened, operated on and then closed, one after the other.

Loops are created via Sequence.Loop():

using (Sequence.Create())
{
    mock.Setup(_ => _.Method1()).InSequence();

    using (Sequence.Loop())
    {
        mock.Setup(_ => _.Method2()).InSequence();
        mock.Setup(_ => _.Method3()).InSequence();
    }
    ...
}

The above checks that Method1 is called by any number of calls to Method2 followed immediately by a call to Method3. You can constrain the number of times the loop can be executed by adding a Times parameter such as the following example where the combination of Method2 and Method3 should be called exactly twice:

using (Sequence.Create())
{
    mock.Setup(_ => _.Method1()).InSequence();

    using (Sequence.Loop(Times.Exactly(2)))
    {
        mock.Setup(_ => _.Method2()).InSequence();
        mock.Setup(_ => _.Method3()).InSequence();
    }
    ...
}

Wrap-Up

Moq.Sequences provides a simple, intentional way of checking that things are are done in a specific order. Feel free to check it out at github. I welcome any feedback!