Custom Matchers in NMock 2.0

This post covers how to write a custom NMock 2.0 Matcher. Matchers are objects that tell NMock 2.0 when two values match. If you have been using NMock 2.0, then you may have been using matchers without realizing it.

This example shows how to use the implicitly use the default matcher. The default matcher makes sure that the calling value and the expected value are equal to each other. Think Object.Equals().


    Expect.Once.On(list).Method("Add").With(2);

Did you see where the matcher is used. Here is the same example, but this time it calls the matcher explicitly.


    Expect.Once.On(list).Method("Add").With(Is.EqualTo(2));

Did you see it that time? A matcher object is returned by the Is.EqualTo() method. Because this is the most common behavior that is desired when writing expectations, the with method is overloaded so that it saves users some typing.

The other matchers that come with NMock 2.0 can be found in the Is class. These are listed below.

  • Is.Anything – returns a matcher that will allow any value to be accepted
  • Is.AtLeast – returns a matcher that will only allow values that are greater than or equal to the specified value
  • Is.AtMost – returns a matcher that will only allow values that are less than or equal to the specified value
  • Is.EqualTo – returns a matcher that will only allow values that are equal to the specified value
  • Is.GreaterThan – returns a matcher that will only allow values that are greater than the specified value
  • Is.LessThan – returns a matcher that will only allow values that are less than the specified value
  • Is.Nothing – returns a matcher that will not allow any value to be accepted
  • Is.NotNull – return a matcher that will accept any value that is not null
  • Is.Null – returns a matcher that will only accept null values
  • Is.Out – returns a matcher that will only accept out values
  • Is.Same – returns a matcher that will only accept the same object that is specified
  • Is.StringContaining – returns a matcher that will only accept things that contain the specified text

Even though there are many matchers that are provided by NMock 2.0, it is very conceivable that these matchers will not always meet your needs. What if you wanted a matcher that accepted a string that matched a regular expression? Or what if you wanted a matcher that only accepted values that were part of specified a collection? What if you wanted a matcher that gave you a reference to the value it received?

There are many more matchers you may need to write while using NMock 2.0. The fact that you can write your own matchers demonstrates just how extensible NMock 2.0 is. This kind of extensibility will help enusure that as your testing needs change, you will be able to extend NMock 2.0 to meet those needs.

For example, NMock 1.0 had a CollectingConstraint class that would accept any parameter, and make it available later in the test. This was useful in cases when complex logic was needed to make sure that the correct value was passed in. I used CollectingConstraint in several tests, and as I was converting I realized that there was no comparable functionality in NMock2. So to bridge this gap, I wrote CollectingMatcher. It provides the same functionality.

Ideally, I should go back and replace the use the CollectingMatcher with a custom Matcher that implements the complex logic in question. But using this matcher works well for migrating from NMock 1.0 to NMock 2.0.

I will show you an example using it, but first, familiarize yourself with the code.


  public class CollectingMatcher: NMock2.Matcher
  {
    private object collected;
    private string name;

    public CollectingMatcher(): this(null)
    {
    }

    public CollectingMatcher(string name)
    {
      this.name = name;
    }

    public override bool Matches(object o)
    {
      this.collected = o;
      return true;
    }

    public override void DescribeTo(System.IO.TextWriter writer)
    {
      if (name != null)
      {
        writer.Write(name);
      }
      else
      {
        writer.Write("< ");
        writer.Write(this.GetType().Name);
        writer.Write(">");
      }
    }

    public object Value
    {
      get
      {
        return collected;
      }
    }
  }

The important thing to note is that the matcher derives from the abstract NMock 2.0 class Matcher, and override the Matches and the DescribeTo methods.

The Matches method is where you put the logic that determines if the value that is passed in matches what the matcher is expecting. In this example, we want to accept every value that is passed in but keep the last one around in the Value property.

The DescribeTo method is used when NMock 2.0 lists the expectations that have not been met. When writing your own matcher you will want to make sure that you put enough information in the DescribeTo method, so that you can debug an unmet expectations.

Now that you have had a chance to dive into the code, lets take a look at an example. This is somewhat of a toy example, because a more meaningful one, would be a little long.

Here is the interface that we are going to use in the example.


  public interface IntegerList {
    void Add(int value);
  }

And here is the example.


  [Test]
  public void TestAdd() {
    Mockery mock = new Mockery();
    IntegerList list = (IntegerList) mock.NewMock(typeof(IntegerList));

    CollectingMatcher matcher = new CollectingMatcher();
    Expect.Once.On(list).Method("Add").With(matcher);

    Collector collector = new Collector(list);
    collector.collect(4);

    Assert.AreEqual(4, matcher.Value);
  }

As you can see, writting Matchers is pretty easy, and a really powerfull way to extend the functionality that is built into NMock 2.0. I hope that you have enjoyed this article. I am working on a second one that covers NMock 2.0 actions.

Tags:

3 Responses to “Custom Matchers in NMock 2.0”

  1. Nat says:

    It’s not a good idea to use Matchers to capture parameters. NMock-2 expects that matchers are stateless. It calls them during the dispatch of every invocation and so you don’t have a guarantee what exactly will be captured. If you want to capture a parameter value, write an *Action* instead.

  2. Nat says:

    One more thing… when writing a custom matcher, it’s considered good style to create a factory method (or at least use a variable) that has a name that reveals what the matcher does. See the jMock tutorial on writing Custom Constraints for more information (http://www.jmock.org/custom-constraints.html).

  3. vaderpi says:

    Thanks for the input, Nat. I will update this tutorial to reflect your comments. And I will include your guidelines in the tutorial as well.

Leave a Reply