(Re)improved argument matchers in Moq

Posted in Moq by bcardiff on the February 23rd, 2009

In the past I wrote about MatcherAttibute in Moq allows developers to create quite easy argument matchers. Due to a suggestion, community opinions and Kzu‘s implementation, the matchers were improved again.

In an scenario with a Customer class and a IFooService:

   1:  public class Customer
   2:  {
   3:      public string Name { get; set; }
   4:      public int Age { get; set; }
   5:      // ...
   6:  }
   7:   
   8:  public interface IFooService
   9:  {
  10:      void Bar(Customer c);
  11:  }

If in a test you need an expectation on Bar method that stands for a Customer c where c.Age >= 18 you
needed to do something like this:

   1:  [Test]
   2:  public void Test1()
   3:  {
   4:      var mock = new Mock<IFooService>(MockBehavior.Strict);
   5:      mock.Setup(x => x.Bar(It.Is<Customer>(c => c.Age >= 18)));
   6:      // this will success
   7:      // mock.Object.Bar(new Customer { Age = 21 });
   8:      // this will fail
   9:      // mock.Object.Bar(new Customer { Age = 17 });
  10:  }

but from now on, using the Matcher factory the same expectation could be written as follows:

   1:  [Test]
   2:  public void Test2()
   3:  {
   4:      var mock = new Mock<IFooService>(MockBehavior.Strict);
   5:      mock.Setup(x => x.Bar(GrownUp()));
   6:      // this will success
   7:      // mock.Object.Bar(new Customer { Age = 21 });
   8:      // this will fail
   9:      // mock.Object.Bar(new Customer { Age = 17 });
  10:  }
  11:   
  12:  public static Customer GrownUp()
  13:  {
  14:      return Match<Customer>.Create(c => c.Age >= 18);
  15:  }

There is some tricky stuff around type here (returning a Match<T> in a method with return type). If you want to see how this work go to the code and read this discussion. All in all is to have a good experience with the compiler.

Continue to read the post and you will see some other alternatives!

Use property as matchers

Last sample could be rewritten with less parenthesis using property getters.

   1:  [Test]
   2:  public void Test2()
   3:  {
   4:      var mock = new Mock<IFooService>(MockBehavior.Strict);
   5:      mock.Setup(x => x.Bar(GrownUp));
   6:      // this will success
   7:      // mock.Object.Bar(new Customer { Age = 21 });
   8:      // this will fail
   9:      // mock.Object.Bar(new Customer { Age = 17 });
  10:  }
  11:   
  12:  public static Customer GrownUp
  13:  {
  14:      get { return Match<Customer>.Create(c => c.Age >= 18); }
  15:  }

More arguments

Also you could have more arguments involved in the matching, just add them as method arguments and use them in the lambda expression.
For example to match older than a certain age:

   1:  [Test]
   2:  public void Test3()
   3:  {
   4:      var mock = new Mock<IFooService>(MockBehavior.Strict);
   5:      mock.Setup(x => x.Bar(OlderThan(18)));
   6:      // this will success
   7:      // mock.Object.Bar(new Customer { Age = 21 });
   8:      // this will fail
   9:      // mock.Object.Bar(new Customer { Age = 17 });
  10:  }
  11:   
  12:  public static Customer OlderThan(int minimumAge)
  13:  {
  14:      return Match<Customer>.Create(c => c.Age >= minimumAge);
  15:  }

Your own helper class

To reuse some matchers, you could define them in a separate a class instead of inside the fixture.

   1:  [Test]
   2:  public void Test4()
   3:  {
   4:      var mock = new Mock<IFooService>(MockBehavior.Strict);
   5:      mock.Setup(x => x.Bar(An.OlderThan(18)));
   6:      // this will success
   7:      // mock.Object.Bar(new Customer { Age = 21 });
   8:      // this will fail
   9:      // mock.Object.Bar(new Customer { Age = 17 });
  10:  }
  11:   
  12:  static class An
  13:  {
  14:      public static Customer OlderThan(int minimumAge)
  15:      {
  16:          return Match<Customer>.Create(c => c.Age >= minimumAge);
  17:      }
  18:  }

Non static method

Finally, the matchers declaration and implementation don’t need to be static. So you could have additional context of matching.
Although I suggest this last only in certain scenarios, for example, match enumeration of values:

   1:  [Test]
   2:  public void Test5()
   3:  {
   4:      var mock = new Mock<IFooService>(MockBehavior.Strict);
   5:      var names = new E("John Doe", "Brian Cardiff");
   6:      mock.Setup(x => x.Bar(names.Some));
   7:   
   8:      // this will success
   9:      // mock.Object.Bar(new Customer { Name = "Brian Cardiff" });
  10:   
  11:      // this will fail
  12:      // mock.Object.Bar(new Customer { Name = "Sandy" });
  13:  }
  14:   
  15:  public class E
  16:  {
  17:      string[] names;
  18:      public E(params string[] names)
  19:      {
  20:          this.names = names;
  21:      }
  22:   
  23:      public Customer Some
  24:      {
  25:          get { return Match<Customer>.Create(s => names.Contains(s.Name)); }
  26:      }
  27:  }

More lines in matcher code

There is no need that the matcher code is a one-line lambda, in case you are not familiar writing lambdas, here is another sample:

   1:  [Test]
   2:  public void Test6()
   3:  {
   4:      var mock = new Mock<IFooService>(MockBehavior.Strict);
   5:      mock.Setup(x => x.Bar(Between(20, 30)));
   6:      // this will success
   7:      // mock.Object.Bar(new Customer { Age = 25 });
   8:      // this will fail
   9:      // mock.Object.Bar(new Customer { Age = 40 });
  10:  }
  11:   
  12:  private Customer Between(int from, int to)
  13:  {
  14:      return Match<Customer>.Create(c =>
  15:      {
  16:          if (c.Age < from)
  17:              return false;
  18:          if (c.Age > to)
  19:              return false;
  20:          return true;
  21:      });
  22:  }

Improved argument matchers in Moq

Posted in Moq by bcardiff on the April 14th, 2008

The new feature encapsulated by MatcherAttibute in Moq allows developers to create quite easy argument matchers.

In a scenario with a Customer class and a IFooService:

public class Customer
{
    public string Name { get; set; }
    public int Age { get; set; }
    // …

}

public interface IFooService
{
    void Bar(Customer c);
}
 

If in a test you need an expectation on Bar method that stands for a Customer c where c.Age >= 18 you
needed to do something like this:

[Test]
public void Test1()
{
    var mock = new Mock<IFooService>(MockBehavior.Strict);
    mock.Expect(x => x.Bar(It.Is<Customer>(c => c.Age >= 18)));
    // …

}
 

but from now on, using the MatcherAttribute the same expectation could be written as follows:

[Test]
public void Test1()
{
    var mock = new Mock<IFooService>(MockBehavior.Strict);
    mock.Expect(x => x.Bar(GrownUp()));
    // …

}

[Matcher]
public static Customer GrownUp() { return null; }
public static bool GrownUp(Customer c)
{
    return c.Age >= 18;
}

Lets call the first GrownUp method as Matcher declaration, and the second Matcher implementation.

  • Matcher declaration must has return type Customer in order to allow the expectation to compile, and be applied the MatcherAttribute.
  • Matcher implementation is used in the actual match, receiving the Customer to be matched and returning the result of the match.
  • Matcher declaration is never executed by Moq, it is used to have clear syntax.

More arguments

Also you could have more arguments involved in the matching, just add the at the end of both declaration and implementation.
For example to match older than a certain age:

[Test]

public void Test1()
{
    var mock = new Mock<IFooService>(MockBehavior.Strict);
    mock.Expect(x => x.Bar(OlderThan(18)));
    // …
}

[Matcher]
public static Customer OlderThan(int minimumAge) { return null; }

public static bool OlderThan(Customer c, int minimumAge)
{
    return c.Age >= minimumAge;
}

Your own helper class

To reuse some matchers, you could define them in a separate a class instead of inside the fixture.

[Test]
public void Test1()
{
    var mock = new Mock<IFooService>(MockBehavior.Strict);
    mock.Expect(x => x.Bar(An.OlderThan(18)));
    // …
}

static class An
{
    [Matcher]
    public static Customer OlderThan(int minimumAge) { return null; }
    public static bool OlderThan(Customer c, int minimumAge)
    {
        return c.Age >= minimumAge;
    }
}
 

Non static method

Finally, the matchers declaration and implementation don’t need to be static. So you could have additional context of matching.
Although I suggest this last only in certain scenarios, for example, match enumeration of values:

[Test]
public void Test2()
{
    var mock = new Mock<IFooService>(MockBehavior.Strict);
    var names = new E(new [] { “John Doe”, “Brian Cardiff” });
    mock.Expect(x => x.Bar(names.Some()));

    // this will success

    // mock.Object.Bar(new Customer { Name = “Brian Cardiff” });

    // this will fail
    // mock.Object.Bar(new Customer { Name = “Sandy” });
}

public class E
{
    IEnumerable<string> names;
    public E(IEnumerable<string> names)
    {
        this.names = names;
    }

    [Matcher]
    public Customer Some() { return null; }
    public bool Some(Customer s)
    {
        return names.Contains(s.Name);
    }
}