Kash Farooq's software development blog

.NET Developer

Posts Tagged ‘Moq’

Checking what was sent to a mock, readability of test code and readability of assert messages

Posted by Kash Farooq on August 7, 2009

There are several ways to determine what was sent to your mock object.
In this blog post I’ll look at using Rhino Mocks and Moq to test the same piece of code and check that the correct data was sent to a dependency. I’ll then also look at not bothering with a Mocking Framework, and just using a Fake instead.

If the method being called on the mock receives a simple type, it is easy to check that the correct data was sent to the mock. For example, with Rhino Mocks:

dependency.AssertWasCalled(m=>m.MyMethod(5));

However, things aren’t as simple if MyMethod receives a complex type.

For the examples below, here is the code under test. I have a dependency that receives a complex type:

//A complex type
public class PersonDetail {
   public string Name { get; set; }
   public string Address { get; set; }
}

//The dependency
public interface IPersonDetailsRepository {
   void StorePersonDetails(PersonDetail personDetail);
}

public class SystemUnderTest
{
    private readonly IPersonDetailsRepository repository;
    public SystemUnderTest(IPersonDetailsRepository repository) {
        this.repository = repository;
    }
}

public void CreatePerson(string name, string address) {
   //intentional bug (address and name the wrong way around) so that we can check the test failure messages
   repository.StorePersonDetails(new PersonDetail {Name = address, Address = name});
}

Rhino Mocks Matches syntax

With Rhino Mocks, one way to check the parameter sent to StorePersonDetails is to use the Matches syntax.

[Test]
public void CheckPersonDetailsAreSaved_RhinoMocks_ArgsMatches()
{
    const string personAddress = "London";
    const string personName = "John Smith";

    var repository = MockRepository.GenerateStub<IPersonDetailsRepository>();
    new SystemUnderTest(repository).CreatePerson(personName, personAddress);

    repository.AssertWasCalled(x => x.StorePersonDetails
                                     (Arg<PersonDetail>.Matches(person => person.Name == personName)));

    //Error: 
    //Rhino.Mocks.Exceptions.ExpectationViolationException:
    //IPersonDetailsRepository.StorePersonDetails(y => (y.Name = "John Smith")); Expected #1, Actual #0.
}

So, we caught the bug. However, I’d argue that it is not at all clear why the test failed. You’d have to look at the code under test. You cannot work out what went wrong by just looking at the error message. Is the error message telling us the dependency was not called at all, or that the argument sent was incorrect?

Rhino Mocks GetArgumentsForCallsMadeOn

The next Rhino Mocks method I’ll look at is one that I’ve discussed before. I think GetArgumentsForCallsMadeOn gives you a much clearer way to understand why your test failed:

[Test]
public void CheckPersonDetailsAreSaved_RhinoMocks_GetArgumentsForCallsMadeOn() {
    const string personAddress = "London";
    const string personName = "John Smith";
            
    var repository = MockRepository.GenerateStub<IPersonDetailsRepository>();
    new SystemUnderTest(repository).CreatePerson(personName,personAddress);

    var objectSentToRepository = (PersonDetail)repository
                                                  .GetArgumentsForCallsMadeOn
                                                       (r => r.StorePersonDetails(null))[0][0];
    Assert.That(objectSentToRepository.Name,Is.EqualTo(personName));
            
    //Error
    //NUnit.Framework.AssertionException:   Expected string length 10 but was 6. Strings differ at index 0.
    //Expected: "John Smith"
    //But was:  "London"
}

The error message you see in your test runner is clear – you know exactly what the bug in the code is. Much clearer than using the Matches syntax. However, you need an explicit cast and you are tying the test to the implementation in terms of parameter order of the dependency (see the caution at the bottom of my post about GetArgumentsForCallsMadeOn).

Moq

With Moq you also get an unclear assert error message:

[Test]
public void CheckPersonDetailsAreSaved_Moq() {
    const string personAddress = "London";
    const string personName = "John Smith";
    var repository = new Mock<IPersonDetailsRepository>();

    new SystemUnderTest(repository.Object).CreatePerson(personName, personAddress);

    //Both these give the same error seen below.
    repository.Verify(r=>r.StorePersonDetails(Match<PersonDetail>.Create(person => person.Name == personName)));
    repository.Verify(r=>r.StorePersonDetails(It.Is<PersonDetail>(x=>x.Name==personName)));

   //Error:
   //Moq.MockException: 
   //Invocation was not performed on the mock: 
   //x => x.StorePersonDetails(Match`1.Create(x1 => (x1.Name = "John Smith")))
}

Again, is the error message telling us the dependency was not called at all?

Fakes

There is another way. If your dependency interface is small, why not use a Fake object? – i.e. don’t use a Mocking Framework at all:

private const string personAddress = "London";
private const string personName = "John Smith";

private class FakeRepository : IPersonDetailsRepository {
    public PersonDetail CollectedPersonDetails;
    public void StorePersonDetails(PersonDetail personDetail) {
        CollectedPersonDetails = personDetail;
    }
}

[Test]
public void CheckPersonDetailsAreSaved_Moq() {
    var fakeRepository = new FakeRepository();
    new SystemUnderTest(fakeRepository).CreatePerson(personName, personAddress);

    Assert.That(fakeRepository.CollectedPersonDetails.Name, Is.EqualTo(personName));

    //Error:
    //NUnit.Framework.AssertionException:   Expected string length 10 but was 6. Strings differ at index 0.
    //Expected: "John Smith"
    //But was:  "London"
}

Using a fake, we have a simple, readable test and when there is an assert failure, it is obvious what the bug is.

Posted in Moq, Rhino Mocks, Test Driven Development | Tagged: , , | 1 Comment »

Recursive Mocks: Comparing Moq to Rhino Mocks

Posted by Kash Farooq on July 28, 2009

Here is the simple ASP.NET MVC code I want to test.
In a test, I need to mock the HttpContext so that it returns an identity that I control.

public ContentResult ReturnUserName() {
   return Content(User.Identity.Name);
}

And here is the test code using the released binaries of Rhino Mocks 3.5:

[Test]
public void ContentContainingUserNameReturned_RhinoMock() {
   var mockContext = MockRepository.GenerateStub<ControllerContext>();
   var mockHttpContext = MockRepository.GenerateStub<HttpContextBase>();
   mockContext.HttpContext = mockHttpContext;
   var identity = new GenericIdentity("user");
   mockHttpContext.User = new GenericPrincipal(identity,null);

   var controller = new HomeController {ControllerContext = mockContext};
   ContentResult content = controller.ReturnUserName();

   Assert.That(content.Content, Is.EqualTo("user"));
}

That’s a fair amount of mocking to test a one line method.

Here is the test using Moq:

[Test]
public void ContentContainingUserNameReturned_Moq() {
   var mockContext = new Mock<ControllerContext>();
   mockContext
     .SetupGet(x => x.HttpContext.User.Identity.Name)
     .Returns("user");

   var controller = new HomeController {ControllerContext = mockContext.Object};
   ContentResult content = controller.ReturnUserName();

   Assert.That(content.Content, Is.EqualTo("user"));
}

Far more concise.

The feature that allows Moq to do this is called Recursive Mocks.
You could argue that if you need to do this in your code then you must be breaking the Law Of Demeter. Sometimes, as with HttpContext, you don’t have a choice. Ayende argues you are breaking this law, but has introduced Recursive Mocking in Rhino Mocks, along with guidance. You’ll have to download the code and build you own binaries to use it though.

Posted in Moq, Rhino Mocks, Test Driven Development | Tagged: , , , , | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.