Rhino.Mocks 3.6 Intro – What You Actually Need To Know

October 21, 2009 09:28 | ALT.Net, Programming

What’s a Mock?

For the purpose of this essay a mock is an object that uses the object oriented concept of polymorphism to create an alternate implementation of a class or interface. Essentially, a mock is just a fake version of an object.

A mock is used for two things

  1. Stub: Stand in for a service and provide alternate, simpler method implementations. An example would be to substitute for an object that would normally query the database – instead of querying the database the stub object will simply return a canned response.
  2. Spy: Detect whether an object was used in a certain way. An example would be when testing an object that decides whether to call ui.NotifyUser() depending on some criteria. A spy can stand in for the ui object and call tell you if the NotifyUser() method was called.
  3. Don’t worry if that is a bit obtuse, it should become clear soon

Why Would You Need A Mock?

Consider the domain of liquid storage.

  • We have a Container which has Contents.
  • By totalling all the transfers into and out of the container we can calculate the expected Quantity of the Contents – this is called the Book Value.
  • We can also physically measure the Quantity – whenever we do, we add the measured Quantity, along with it’s type (whether it was taken Automatically or Manually) to the store of Physicals.
  • We can at any time request a measurement of the Variance of the Contents. This Quantity is defined as the last manual Physical minus the Book Value.
  • Of course when a Varaiance is calculated, it needs to get Logged.
  public class Contents {
          public Quantity Book { get; set; }
  }
  public interface IPhysicals {
    Quantity GetLastFor(Contents contents, PhysicalType physicalType);
  }
  public enum PhysicalType { Manual, Automatic }
  public class Quantity {
     public double Amount { get; set; }
    public string UnitOfMeasure { get; set; }
  }
  public interface IEventLogger {
    void Log(string message);
  }
  public class VarianceCalculator {
    IPhysicals _physicals;
    IEventLogger _log;
    public VarianceCalculator(IPhysicals physicals, IEventLogger events) {
      _physicals = physicals;
      _log = events;
    }

    public Quantity GetVariance(Contents contents) {
      Quantity p = _physicals.GetLastFor(contents, PhysicalType.Manual);
      if (p == null)
        return null;
      var variance = new Quantity() { Amount = p.Amount - contents.Book.Amount };
      _log.Log(String.Format("New variance calculated: {0} - {1} = {2}",
               p.Amount, contents.Book.Amount, variance.Amount));
      return variance;
    }
  }

[Code Link]

The only logic here is in the VarianceCalculator.GetVariance method so let’s test that.

For any action there are two things that can be checked: the output, and any side-effects. So let’s write down all the conditions and side-effects that we expect.

  1. If the contents object does have a manual physical then the method should return the correctly calculated quantity
  2. If the contents object does have a manual physical then the method should log the calculation.
  3. If the contents object does not have a manual physical then the method should return null
  4. If the contents object does not have a manual physical then the method should not log anything.

Notice that an external service (IPhysicals) is used to retrieve the physical that will be used. We do not want to actually have to set up and query the database so we need something that performs the duties of a stub. Also notice that we need to check whether the calculation results were passed off to a logger object. Going on our definitions from above, this requires a spy.

Our Tests

Given that we have four points above we should write four tests. Here they are written in an abstract class that leaves gaps for how to to actually set-up the mocks. We will create implement this abstraction in the next two sections.

  [TestFixture]
  public abstract class VarianceCalculatorTests {
    protected abstract void BuildMocks(Quantity lastManualPhysical);
    protected abstract VarianceCalculator GetCalculator();
    protected abstract void AssertLoggerWasCalled(bool expectLoggerCalled);

    readonly Contents _contents = new Contents() {
      Book = new Quantity() { Amount = 700 }
    };

    [Test]
    public void Has_physical__Variance_is_physical_minus_book() {
      BuildMocks(new Quantity() { Amount = 1000 });
      var variance = GetCalculator().GetVariance(_contents);
      Assert.That(variance.Amount, Is.EqualTo(300));
    }
    [Test]
    public void Has_physical__Calculation_is_logged() {
      BuildMocks(new Quantity());
      GetCalculator().GetVariance(_contents);
      AssertLoggerWasCalled(true);
    }
    [Test]
    public void Has_no_physical__Variance_is_null() {
      BuildMocks(null);
      var variance = GetCalculator().GetVariance(_contents);
      Assert.IsNull(variance);
    }
    [Test]
    public void Has_no_physical__Calculation_is_not_logged() {
      BuildMocks(null);
      GetCalculator().GetVariance(_contents);
      AssertLoggerWasCalled(false);
    }
  }

[Code Link]

Doing It Manually

In the interest of going slow, let’s first implement the above test fixture manually.

MOCKS CANNOT DO ANYTHING THAT YOU CANNOT DO YOURSELF MANUALLY!

If you do not need any further convincing then you can skip to the next section.

When you manually create an alternate implementation the resulting objects are traditionally called “Fakes”. Here is a fake implementation of IPhysicals that can stub out calls to physicals.GetLastFor()

  public class FakePhysicalsStub : IPhysicals {
    private Quantity _lastPhysical;
    public FakePhysicalsStub(Quantity lastPhysical) {
      _lastPhysical = lastPhysical;
    }
    public Quantity GetLastFor(Contents contents, PhysicalType physicalType) {
      return _lastPhysical;
    }
  }

And here is a fake implementation of an IEventLogger spy:

  public class FakeEventLoggerSpy : IEventLogger {
    private IList<string> _messagesLogged = new List<string>();
    public void Log(string message) {
      _messagesLogged.Add(message);
    }
    public bool WasLogged(Regex expectedMessageMatcher) {
      return _messagesLogged.Any(m => expectedMessageMatcher.IsMatch(m));
    }
  }

And here is how you would use these:

  public class ManualFakes_VarianceCalculatorTests : VarianceCalculatorTests {
    private FakeEventLoggerSpy _logger;
    private FakePhysicalsStub _physicals;
    protected override void BuildMocks(Quantity lastManualPhysical) {
      _physicals = new FakePhysicalsStub(lastManualPhysical);
      _logger = new FakeEventLoggerSpy();
    }

    protected override VarianceCalculator GetCalculator() {
      return new VarianceCalculator(_physicals, _logger);
    }

    protected override void AssertLoggerWasCalled(bool expectLoggerCalled) {
      Assert.That(_logger.WasLogged(new Regex(".+")), Is.EqualTo(expectLoggerCalled));
    }
  }

[Code Link]

Getting Rhino.Mocks to Do It for You

Creating fakes manually is not very difficult but it does require some thought. In addition you end up having to maintain the fakes as well as your actual implementations when making any changes to the underlying types. On the other hand, creating manual fakes will always be more powerful and flexible than an automatic alternative so do not be afraid to use them when needed. That being said, Rhino Mocks is a library thatwhen properly used should be able to cover 99% of your automatic mock creation needs. In fact, I have never really encountered a situation where its abilities proved inadequate.

It is important to remember that Rhino.Mocks has been around for some time and offers several different APIs. This tutorial targets the version of the API as of Rhino.Mocks 3.6 – while improvements are possible, there have not been any truly major changes in the last few versions and this API style can probably be considered final.

Mock Creation

First things first; how do you use Rhino.Mocks to create our stub and spy instances? Rhino.Mocks does not distinguish between the two when creating objects – all classes created by Rhino.Mocks can be used as both stubs and spys. The easiest way to create them is to use the MockRepository static class:

This class has two methods of consequence, GenerateMock<T>() and GenerateStub<T>(). There is very little difference between these two and you can feel perfectly safe using only GenerateStub<T>(). Calling

IEventsLogger mock = MockRepository.GenerateStub<IEventsLogger>()

Will return an that implements IEventsLogger and can stand in for all its instances.

Stubbing

By default, any calls to _physicals.GetLastFor() will return null but we can set up this mock object to act as a stub:

  _physicals = MockRepository.GenerateStub<IPhysicals>();
  _physicals.Stub(x => x.GetLastFor(
      Arg<Contents>.Is.Anything, Arg<PhysicalType>.Is.Anything) ).Return(lastManualPhysical);

This API uses extension methods and LINQ Expressions to allow you to specify which method you want to stub and what to return. When _physicals.GetLastFor() is called after this code executes, the object lastManualPhysical will be returned.

Also, as the above code implies, you can constrain the stub based on certain types of inputs.

  _physicals.Stub(x => x.GetLastFor(
      Arg<Contents>.Is.Null, Arg<PhysicalType>.Is.Equal(PhysicalType.Automatic))).Return(someOtherPhysical);

Is legal and works pretty much like you would expect. Many constraint types are available. There are also several shortcuts. For example the above can be expressed as

_physicals.Stub(x => x.GetLastFor(null, PhysicalType.Automatic).Return(someOtherPhysical);

Since all arguments have to be matched exactly. Also the first stub (where any arguments are acceptable) can be more quickly expressed as:

_physicals.Stub(x => x.GetLastFor(null, null)).IgnoreArguments().Return(lastManualPhysical);

Several other syntaxes are also available, but as of Rhino.Mocks 3.6 these are the only ones that are preferred.

Spying

Now that we have discussed stubbing, let’s discuss the syntax for creating spy objects. As stated before, all objects created with Rhino.Mocks can be both stubs and spys so their creation is exactly the same. We only need to learn the syntax for how to verify whether a method was called or not. This is achieved with the AssertWasCalled() and AssertWasNotCalled() extension methods.

These methods have very similar syntax to Stub() with the exception that IgnoreArguments(), and other constraints shortcuts are provided in a constraints parameter, rather than as extension methods of their own. So, to specify that our IEventsLogger.Log() method was called we need to do this:

_logger.AssertWasCalled(x => x.Log(null), c => c.IgnoreArguments());

Or to specify that it was not called:

_logger.AssertWasNotCalled(x => x.Log(null), c => c.IgnoreArguments());

If you want a little more finely grained control over the argument constraints you can do that too. For example the following asserts that Log() was called and that the input was not null or empty:

  _logger.AssertWasCalled(x => x.Log(
    Arg<string>.IsMatches(Is.Matching<string>(m => !String.IsNullOrEmpty(m)))));

Of course, as before, if you know the exact argument that you want to check for you can do it more easily:

_logger.AssertWasCalled(x => x.Log("this exact message was called"));

Here is the full implementation for the base VarianceCalculatorTests:

  public class RhinoMocks_VarianceCalculatorTests : VarianceCalculatorTests {
    private IEventLogger _logger;
    private IPhysicals _physicals;
    protected override void BuildMocks(Quantity lastManualPhysical) {
      _physicals = MockRepository.GenerateStub();
      _physicals.Stub(x => x.GetLastFor(Arg.Is.Anything, Arg.Is.Anything)).Return(lastManualPhysical);
      _logger = MockRepository.GenerateStub();
    }

    protected override VarianceCalculator GetCalculator() {
      return new VarianceCalculator(_physicals, _logger);
    }

    protected override void AssertLoggerWasCalled(bool expectLoggerCalled) {
      if (expectLoggerCalled)
        _logger.AssertWasCalled(x => x.Log(null),
            c => c.Constraints(Is.Matching(m => !String.IsNullOrEmpty(m))));
      else
        _logger.AssertWasNotCalled(x => x.Log(null), c => c.IgnoreArguments());
    }
  }

[Code Link]

Other Stuff

You have now learned virtually everything you need to know to effectively use Rhino.Mocks. A couple other occasionally used syntaxes are:

  _physicals.Stub(x => x.GetLastFor(null,
    Arg<PhysicalType>.Is.Anything)).Throw(new ArgumentNullException ());

Which causes (you guessed it) an ArgumentNullException to be thrown when GetLastFor() is passed a null contents object.

If you have played around with the stubbing code above, you might have noticed that the stub will work only once. That is, you will get the desired result the first time you call _physicals. GetLastFor() but will go back to returning null for subsequent calls. To get the desired result you can set the stub up multiple times, or use the Repeat syntax.

  _physicals.Stub(x => x.GetLastFor(null,
    Arg<PhysicalType>.Is.Anything)).Return(null).Repeat.Any();

Also, you can pass in a delegate to be executed when a stubbed method is called. This is primarily useful when doing integration and benchmark tests or when working with a timer.

  _physicals.Stub(x => x.GetLastFor(null, PhysicalType.Automatic)).IgnoreArguments().Do(
    new Func<Contents, PhysicalType, Quantity>((c, t) => {
      Console.WriteLine("Method Called With {0}, {1}", c, t);
      return null;
    })
  );

A situation where you are finding yourself having to do something like this might be an indicator that you should just create a fake manually.

It is also possible to create mocks of concrete classes rather than just interfaces. However, this can be a little tricky since there is no way for Rhino.Mocks to stop the constructor from executing. You must therefore either provide a parameter-less protected constructor or pass in objects to be used.

  public class MyClass {
    string _dependency;
    public MyClass(string dependency) {
      _dependency = dependency;
    }
  }
  //
  MyClass x = MockRepository.GenerateStub<MyClass>("");

A word of caution however, if you find yourself really needing to mock a concrete object perhaps you might want to consider extracting an interface, or including the object in your test.

And that’s it. There is a lot of other stuff in Rhino.Mocks but it is almost guaranteed that you don’t need to know it as the above will cover nearly every single testing scenario.

Sample Code and on Testing Style

The sample code from this tutorial is provided here. Please note that there are three sets of tests. VarianceCalculatorTests.cs contains the base class which defines the tests used above. ManualFakes_VarianceCalculatorTests implement the tests using manually built fakes and RhinoMocks_VarianceCalculatorTests implements them using Rhino.Mocks.

Although it is ultimately a matter of preference, it should be noted that the tests written so far are not done in what in what is a somewhat dated style. The currently predominant testing technique of Behavior Driven Development (BDD) is usually preformed and recommended. To that end, another series of tests is provided inside the BDD directory to demonstrate how such tests might look.

So now you know how to use Rhino.Mocks. I urge you to investigate its use further and learn as much as you can about Unit Testing, Test Driven Development, and Behavior Driven Development.

Please feel free to leave any further questions in the comments.

Tags: , , , ,

Comments

What an excellent article. i was looking 3.6 tricks and I found them here. Your section on Spying was especially relevant

Thanks
Adnan

/ Adnan
March 5, 2010, 15:55

Write a comment: