Using Moq to check the values of an object passed to a method

In order to test individual properties of an object passed to a method using Moq I have been making use of my Assert.IsFieldEqual method. See here for details.

Because I can’t call the Assert.IsFieldEqual inside a lambda, like so …


    _mockBus
        .Verify(x => x.Send(It.Is<MyMessage>(m => Assert.IsFieldEqual(m, propertyName, expectedValue))), Times.Once());

Obviously, since makes no sense as the Assert.IsFieldEqual is a void method. So, I’ve made use of Moq’s callback facility.


    MyMessage sentMessage = null;

    _mockBus
        .Setup(x => x.Send(It.IsAny<MyMessage>()))
        .Callback<object>((m) => sentMessage = (MyMessage) (((object[]) m)[0]));

    Assert.IsFieldEqual(sentMessage, propertyName, expectedValue);

This allows me to have a TestCase for each property in the message, so I have one test method for all the properties.

Advertisements

I’m all Moq’d out!

I’m currently working on creating a Hypermedia API, or at least getting as close as I can to one!

In order to avoid the client hitting a dead end when an error occurs, either internally within my code or as a result of a bad request from the client, I wanted to provide links that the client can follow. So, I created an ApiError model class to send in my response in such a case.

    [Hypermedia]
    public class ApiError : Resource
    {
        public string ParentId { get; set; }
        public string ErrorMessage { get; set; }
    }

The [Hypermedia] attribute is just a place holder I use within my Delegating Handler which “enriches” the resources with links. The ParentId is the id used in order to construct links to the home resource and it’s also used for constructing self links and so on.

The links are generated by way of Mark Seamann’s excellent HyprLinkr library, available via Nuget (http://nuget.org/packages/Hyprlinkr/).

My first attempt was to create an extension method to create the response, much like the built in HttpRequestMessage.CreateErrorResponse extension method. This worked great when I tested it using my current favourite chrome extension, POSTman. It returned the error, along with a “back” and “home” link so the client didn’t just hit a dead-end.

For example …

  "errorMessage" : "The was an error, run for the hills!",
  "_links" :
  [
    {
      "rel" : "home",
      "href" : "http://server/api/home/someone@example.com",
      "title" : "home",
      "verb" : "GET"
    }
  ]

So, all is well. I’m a happy bunny….

Until I run my unit tests.

What The Flip?

Why is there red everywhere?!

As it turns out I wrote some legacy (read: un-testable) code. Here’s what I’d come up with …

    public static class HttpRequestMessageExtensions
    {
        public static HttpResponseMessage CreateErrorResponse(
            this HttpRequestMessage request,
            HttpStatusCode statusCode,
            string parentId,
            string errorMessage,
            Action<IResourceLinker, ApiError> addLinks)
        {
            var apiError = new ApiError
            {
                ParentId = parentId,
                ErrorMessage = errorMessage
            };

            if (addLinks != null)
            {
                var routeLinker = _resourceLinkerFactory.GetResourceLinker(request);
                addLinks(routeLinker, apiError);
            }

            return request.CreateResponse(statusCode, apiError);
        }

After spending some time in the debugger trying to figure out why I was getting a null reference exception, I started looking at Mark’s code on github and eventually figured out that the GetRouteData() call was returning null. So, I spent more time trying to figure out a way of getting that to *not* be null. I ended up getting the source code for the aspnetwebstack from codeplex and looking at the code for GetRouteData().

Veering off-topic slightly, I didn’t have git installed on my pc, so I fired up powershell and …

  PS> cinst git

… I used chocolately to install it, restarted powershell and …

  PS> git clone https://git01.codeplex.com/aspnetwebstack

… I was rummaging around the asp.net web stack code ๐Ÿ˜€

Back on to topic …

After a few failed attempts at getting the null reference to go away it dawned on me that with another layer or two or abstraction I could Moq (on nuget too – https://www.nuget.org/packages/moq) my way out of trouble.

So, thinking about it for a little while I came up with a way of doing all this so I could moq it. Firstly I needed to change CreateApiErrorResponse from an extension method into a “service”, which I could then pass into the relevant controllers. Once I get past the unit test stage I could easily set it up using Castle Windsor. I would also need an IResourceLinker factory.

The Service

    public interface IHttpRequestMessageService
    {
        HttpResponseMessage CreateErrorResponse(
            HttpRequestMessage request,
            HttpStatusCode statusCode,
            string parentId,
            string errorMessage,
            Action<IResourceLinker, ApiError> addLinks);
    }

    public class HttpRequestMessageService : IHttpRequestMessageService
    {
        private readonly IResourceLinkerFactory _resourceLinkerFactory;

        public HttpRequestMessageService(IResourceLinkerFactory resourceLinkerFactory)
        {
            _resourceLinkerFactory = resourceLinkerFactory;
        }

        public HttpResponseMessage CreateErrorResponse(
            HttpRequestMessage request,
            HttpStatusCode statusCode,
            string parentId,
            string errorMessage,
            Action<IResourceLinker, ApiError> addLinks)
        {
            var apiError = new ApiError
            {
                ParentId = parentId,
                ErrorMessage = errorMessage
            };

            if (addLinks != null)
            {
                var routeLinker = _resourceLinkerFactory.GetResourceLinker(request);
                addLinks(routeLinker, apiError);
            }

            return request.CreateResponse(statusCode, apiError);
        }
    }

The Factory

    public interface IResourceLinkerFactory
    {
        IResourceLinker GetResourceLinker(HttpRequestMessage request);
    }

    public class ResourceLinkerFactory : IResourceLinkerFactory
    {
        public IResourceLinker GetResourceLinker(HttpRequestMessage request)
        {
            return new RouteLinker(request, new AttributeBasedRouteDispatcher());
        }
    }

Once I sorted out a few built errors it was time to do some Moqing…

    public class MyControllerTests
    {
        private Mock<IResourceLinkerFactory> _mockResourceLinkerFactory;
        private Mock<IResourceLinker> _mockResourceLinker;
        private IHttpRequestMessageService _httpRequestMessageService;
        private MyController _controller;

        [SetUp]
        public void SetUp()
        {
            const string id = "john.doe@example.com";

            var config = new HttpConfiguration();
            var request = new HttpRequestMessage(HttpMethod.Post, string.Format("http://localhost/api/user/{0}", id));

            _mockResourceLinkerFactory = new Mock<IResourceLinkerFactory>();
            _mockResourceLinker = new Mock<IResourceLinker>();
            _httpRequestMessageService = new HttpRequestMessageService(_mockResourceLinkerFactory.Object);

            _mockResourceLinkerFactory.Setup(x => x.GetResourceLinker(It.IsAny<HttpRequestMessage>()))
                                      .Returns(_mockResourceLinker.Object);

            _mockResourceLinker.Setup(x => x.GetUri(It.IsAny<Expression<Action<MyController>>>()))
                           .Returns(new Uri(string.Format("http://localhost/api/user/{0}", id)));

            _controller = new MyController(_httpRequestMessageService);
        }
    }

Hurrah! It all worked and I could get back to testing what I was actually trying to, which was unrelated to providing links when sending errors to the client. But, I needed this anyway ๐Ÿ˜€

Since the tests I was working on weren’t testing the presence of the links, I suppose I could have done something like this …

    var _mockHttpRequestMessageService = new Mock<IHttpRequestMessageService>();
    _mockHttpRequestMessageService
        .Setup(x => x.CreateErrorResponse(
            It.IsAny<HttpRequestMessage>(),
            It.IsAny<HttpStatusCode>(),
            It.IsAny<string>(),
            It.IsAny<string>(),
            It.IsAny<Action<IResourceLinker, ApiError>>())
        .Returns(new HttpResponseMessage(...));

Anyway, I hope that helps someone out. It’ll probably be me at some point in the future as my memory is not the best ๐Ÿ˜‰

Moq and Lazy Loading

I’ve just completed a bit of TDD. Proper TDD, I wrote the code to pass the tests and wrote the tests first. Anyway, one thing I needed control over was the concept of “now”. This particular method I was testing/writing deals with DateTime objects.

I needed a way of defining, on a per test basis, what “now” is. There were two steps to achieving this. Firstly, I needed to use an interface to get “now”.

public interface IDateTimeProvider
{
    DateTime Now { get; }
}

So, rather than using DateTime.Now, I use DateTimeProvider.Now.

The second step is creating the mock IDateTimeProvider and using the lazy loading feature of Moq. In this particular case I am using Moq and a test base class …

[TestFixture]
public abstract class BaseTest
{
    private Mock<IDateTimeProvider> _mockDateTimeProvider;
    protected IDateTimeProvider DateTimeProvider { get { return _mockDateTimeProvider.Object; } }

    [SetUp]
    public void Setup()
    {
        _mockDateTimeProvider = new Mock<IDateTimeProvider>();
        Now = DateTime.MinValue;
        _mockDateTimeProvider.Setup(x => x.Now).Returns(() =>
        {
            if (Now == DateTime.MinValue)
            {
                throw new Exception("'Now' property must be set in each [Test] method");
            }
            return Now;
        });
    }

    protected DateTime Now { private get; set; }
}

So, I have a DateTime property, which is evaluated whenever the IDateTimeProvider.Now method is called. I added a little check to make sure the Now property is set in each test. That, coupled with setting Now to DateTime.MinValue means any test which doesn’t set the value will get a helpful message in your chosen test runner.

The crucial part of that code and what makes it really useful is the lazy evaluation, which is done like so …

() =>
{
    if (Now == DateTime.MinValue)
    {
        throw new Exception("'Now' property must be set in each [Test] method");
    }
    return Now;
}

I’ve also made the Now and _mockDateTimeProvider private so they cannot be used, forcing the use of the DateTimeProvider.

Here is an example test …

[Test]
public void ExampleTest()
{
    Now = DateTime.Parse("30 Nov 2011 15:00");

    // Arrange

    // Act
    var result = DateTimeProvider.Now;

    // Assert
    Assert.That(result, Is.EqualTo(DateTime.Parse("30 Nov 2011 15:00")));
}

I’ve explicitly defined the dates in my asserts so it’s a little more obvious what is going on. I’ve also used DateTime.Parse as it’s easier to read. I’ve put the assignment of the Now property before the Arrange section as it’s really a pre-arrange step.

It’s not totally necessary to require Now to be configured explicitly for each test, but I think it makes things a little easier to read for developers coming to this code fresh. It would be possible to have a default value for “Now” but that isn’t very discoverable.