Rhino Mocks

Rhino Mocks – Starter Guide

Intro

Rhino mocks enables the user to replace code dependencies that the code under test interacts with and depends on. By using Rhino Mocks you are able to control (or at least pre-define) the outputs and responses sent back from the code under test.

Unit Tests shouldn’t be dependent on anything other than what is available to the test in system memory. So any test that interacts with a db, file system or azure storage isn’t a true Unit Test. What Rhino Mocks allows you to do is to pretend you’ve got a file system, db etc… you can interact with it but its contained within the system memory.

The reason you want to be able to work like this way, is so that if you pass a test over to someone else, they don’t need to set up code & db connections etc… for the test to run and work. They should just be able to run the test.

Getting Started

In order to use Rhino Mocks download the latest version from http://hibernatingrhinos.com/open-source/rhino-mocks

For us, download Rhino Mocks to C:\Libraries\RhinoMocks\ so that we have a unified place to look for the dlls to live in. Within the unit test solution file add the reference to the project so that you can use the dll in the solution.

Important – Rhino Mocks cannot be used on methods which are static or sealed. As we’ve got tonnes of static methods littering the libraries we’ve got some refactoring to do before we can use it in anger. On top the the static / sealed issue we also need to change the design of some of our classes so that they are loosely coupled to the objects they use. The first step we need to take is by using interfaces and not explicitly creating objects e.g.

  CloudStorageAccount azureAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

but it should be

  IcloudStorageAccount azureAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

Coding to an Interface

By coding to an interface it allows Rhino Mocks to create an instance/proxy of the object we can use to pass into the code. This allows us to create predefined responses and set up test scenarios that we have control over. We’ve taken away any reliance on systems (dbs, file systems, etc… ) as its being handled in memory.

Dependency Injection

Now that we’re coding to interfaces, we can pass the Rhino Mock objects into the code we’re testing. This can be done via the constructor or a property on the object under test e.g.

  public class HotHouse : IHotHouse
  {
    /// Set up the class
    private IThermometer TemperatureService;

    public HotHouse (IThermometer tempGauage)
    {
      TemperatureService = tempGauage;
    }

    public bool IsHot
    {
      get
      {

        if (TemperatureService.GetTemperature() >= 20)
        {
          return true;
        }
        else
        {
          return false;
        }
      }
      set
      {
        isHot = value;
      }
    }
}

And then when we call the HotHouse Object we can create like so:

     IThermometer Therm = new Thermometer())
     HotHouse hothouse = new HotHouse(Therm);

So what we’ve got is a class which uses a thermometer object and is loosely coupled to it. THIS now allows us to plug in the Rhino Mock Proxy.

A Pause for Mocks vs Stubs

  • Stubs and mocks are the same thing at birth and should be referred to as Fakes.
  • It is when a fake is asserted against that they become a Mock.
  • IF a fake is not asserted on then it is a stub and a stub cannot break your tests.
  • A test can have multiple stubs but should only contain one Mock, as this way, if your test fails you know which mock has broken it (as only Mocks will break a test).
  • It is possible to have different types of Fakes – strict or dynamic. A strict mock will test every eventuality within your object. Best Practice is to not use Strict as they over specify the test e.g. your tests should only be testing one thing and that’s all. As your tests should be specific so that you can instantly tell what has been broken

Taken from Roy Osherove

Arrange Act Assert

Arrange

1. In order to use Rhino mocks add a call to MockRepository.GenerateStub, passing through (injecting) the interface we’re wanting to sub out.

2. Set the value we want to be returned when we, within the object under test, call the injected object.

Act

3. Make the call to the object under test.

Assert

4. Make the assertion we want for the test.

  private const int HOT_TEMPERATURE = 20;

    [Test]
    public void TemperatureInsideTheGreenHouseIsHot()
    {
     // Arrange
      var stub = MockRepository.GenerateStub<IThermometer>();
      stub.Stub(s => s.GetTemperature()).Return(HOT_TEMPERATURE);

      // Act
      HotHouse hothouse = new HotHouse(stub);

      // Assert
      Assert.IsTrue(hothouse.IsHot);

    }

OR we can assert that a method is called due to the conditions we set up for the test.

   [Test]
    public void GetValueBackFromHTTPCurrentUsingRhino()
    {
      //arrange
      string xslPath = @"..\..\commonfiles\files\cms.xsl";
      var fake = MockRepository.GenerateMock<IHTTPContextController>();
      XslCompiledTransform transform = new XslCompiledTransform(true);
      XmlUrlResolver resolver = new XmlUrlResolver();
      XsltSettings settings = new XsltSettings();

      settings.EnableDocumentFunction = true;
      settings.EnableScript = true;
      transform.Load(xslPath, settings, resolver);

      fake.Stub(s => s.GetStoredObject<XslCompiledTransform>(xslPath)).Return(transform);
      fake.Stub(s => s.GetStoredObjectDate(string.Concat(xslPath, "memdate"))).Return(DateTime.UtcNow.AddMinutes(-6));
      Rendering renderingEngine = new Rendering(fake);

      //act      
      transform = renderingEngine.getXsltFromMemory(xslPath);

      //assert
      fake.AssertWasCalled(x => x.SetStoredObjectDate(string.Concat(xslPath, "memdate"), DateTime.MinValue));
      Assert.IsNotNull(transform.OutputSettings);
    }

Arrange

1. Create a Fake Object which is of a Mock type, as we want it to fail the test (…remember stubs can’t fail a test)

2. Set up the actions we want to happen if we call certain code in the object under test. In this case, return a XLST file and also the date it was stored into memory

3. Pass the fake object though to the class under test.

Act

4. Make the call to the object under test.

Assert

5. Check that the call to SetStoredObject was called with the appropriate date. If it was then we know that due to the conditions we passed through, via Rhino Mocks, to the object under test has caused the method to be called.

Useful Links / Web Casts / Resources

Leave a comment