Sunday, November 4, 2012

Messing around with Generics

The other day I was looking through some code and thought of a way to refactor the code using generics.  I decided to create an example with the code in its current form and then see if I could make it work more generically. All the source can be found here (https://github.com/devdaves/genericconditions) on GitHub.

Here is the code example prior to using generics:

public ExampleResponse ValidateExampleWithoutGenerics(ExampleRequest request)
{
    ExampleResponse response = new ExampleResponse();

    Condition1(request, ref response);
    Condition2(request, ref response);
    Condition3(request, ref response);
    //could be many conditions...
    DoWork(request, ref response);

    return response;
}

The method accepts a request object and returns a response object.  There are several conditions that need to be validated prior to doing the work.  All condition and do work methods check the status property in the response prior to doing any work.  This way if Condition1 fails the rest of the methods will still be executed but the work will not be done since the status of the response is checked in each method.

What I am trying to solve is not running the other conditions or do work if the response status is in a faulted state.  Now I know I could just add some conditions into this method but what's the fun in that.  So time to refactor.

First the response needs to inherit from an IResponse that enforces that all responses will have a status property.  This will come in handy when we create the generic method a little later in the post.

public interface IResponse
{
    Status Status { get; set; }
}

Next rewrite the Validate method with generics.  Note the list of actions.

public ExampleResponse ValidateExampleWithGenerics(ExampleRequest request)
{
    ExampleResponse response = new ExampleResponse();

    List<Action<ExampleResponse>> todo = new List<Action<ExampleResponse>>()
    {
        {(r) => {Condition4(request, ref r);} },
        {(r) => {Condition5(request, ref r);} },
        {(r) => {Condition6(request, ref r);} },
        {(r) => {DoWork2(request, ref r);} },
    };

    //DoToDo<ExampleResponse>(todo, ref response);
    todo.RunWithShortCircuit(ref response);

    return response;
}

Initially the list of actions was sent to a method in the same class (DoToDo now commented out) and later turned into an extension method.  This is the extension method.

public static void RunWithShortCircuit<T>(this List<Action<T>> actions, ref T response)
    where T : IResponse
{
    foreach (var action in actions)
    {
        if (response.Status.StatusCode == 0)
        {
            action.Invoke(response);
        }
        else
        {
            // short circuits the rest of the actions from running
            break;
        }
    }
}

This extension method will work off any list of actions that inherit from the IResponse interface created earlier.  It will loop through the actions and execute each one and check the status.  If the status is in a faulted state it will stop processing the list of actions.  Since this is now generic any method we create in the project that uses the request/response pattern should be able to use this extension method to execute the conditions and dowork.

The cool thing here is not only are we short circuiting the process but each condition and dowork method no longer needs to check the status since its done in one place.  If the logic that checks the status is done in only one place the maintenance of the code is much easier.

I have to admit that I haven't spent a lot of time playing with generics like this but I can see from a maintenance point of view that it can save some substantial time in a decent sized project.  Plus I really like the way it reads although it does take some time to get used to.

Wednesday, May 30, 2012

Moq: Mocking HttpContext in your MVC3 unit tests

Lets take the following action method on our Home controller.

public ActionResult TestAction()
{
    var idFromCookie = Request.Cookies["ID"].Value;
    var model = new TestActionViewModel() { Id = idFromCookie };
    return View("TestAction", model);
}

Unit testing this action method can be difficult due to its dependency on the Request object.  Luckily the Request object here maps to the HttpContext of the controller.  The HttpContext on the controller is an instance of HttpContextBase and can be mocked in unit tests.

Below is a class I currently use to mock out the HttpContext.  Note that I have many other properties mocked that are part of the HttpContext.  I plan on doing other blog posts using those different properties in the future.

using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;

public class MockContext
{
    public Mock<RequestContext> RoutingRequestContext { get; private set; }
    public Mock<HttpContextBase> Http { get; private set; }
    public Mock<HttpServerUtilityBase> Server { get; private set; }
    public Mock<HttpResponseBase> Response { get; private set; }
    public Mock<HttpRequestBase> Request { get; private set; }
    public Mock<HttpSessionStateBase> Session { get; private set; }
    public Mock<ActionExecutingContext> ActionExecuting { get; private set; }
    public HttpCookieCollection Cookies { get; private set; }

    public MockContext()
    {
        this.RoutingRequestContext = new Mock<RequestContext>(MockBehavior.Loose);
        this.ActionExecuting = new Mock<ActionExecutingContext>(MockBehavior.Loose);
        this.Http = new Mock<HttpContextBase>(MockBehavior.Loose);
        this.Server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
        this.Response = new Mock<HttpResponseBase>(MockBehavior.Loose);
        this.Request = new Mock<HttpRequestBase>(MockBehavior.Loose);
        this.Session = new Mock<HttpSessionStateBase>(MockBehavior.Loose);
        this.Cookies = new HttpCookieCollection();

        this.RoutingRequestContext.SetupGet(c => c.HttpContext).Returns(this.Http.Object);
        this.ActionExecuting.SetupGet(c => c.HttpContext).Returns(this.Http.Object);
        this.Http.SetupGet(c => c.Request).Returns(this.Request.Object);
        this.Http.SetupGet(c => c.Response).Returns(this.Response.Object);
        this.Http.SetupGet(c => c.Server).Returns(this.Server.Object);
        this.Http.SetupGet(c => c.Session).Returns(this.Session.Object);
        this.Request.Setup(c => c.Cookies).Returns(Cookies);
    }

}

In the constructor I new up the new mocks and do some wiring up of the dependencies of the objects you will need while working with the HttpContext.  Since the above action uses a cookie, note that there is a Cookies property that is mapped to the mocked request object.  So when Request.Cookies is called in the action method it will actually be looking at the Cookies collection defined in this class.

Here is a test that uses the MockContext object to test the action method above.

[TestMethod]
public void TestActionCookieValueReturnedInModel()
{
   //arrange
    var expectedValue = "TEST";
    MockContext mockContext = new MockContext();
    mockContext.Cookies.Add(new HttpCookie("ID", expectedValue));
    var homeController = new HomeController()
        {
            ControllerContext = new ControllerContext()
                {
                    HttpContext = mockContext.Http.Object
                }
        };

    //act
    var result = homeController.TestAction() as ViewResult;
    var model = result.ViewData.Model as TestActionViewModel;

    //assert
    Assert.AreEqual(expectedValue, model.Id);
}

Note that I new up a new instance of the MockContext and add the cookie to the cookie collection so the action method above will have access to it.  When creating an instance of the controller I used an object initializer to set the controller context to a new controller context using our MockContext http object.

Using this technique it would be very easy to mock out what would happen if the cookie was not in the cookies collection.

Monday, May 28, 2012

Moq: Adding Setups/Expectations work after providing object to Dependent

First some background code.

Lets assume we have a contact repository interface like so:

public interface IContactRepository
{
    Contact Add(Contact contact);
    bool Exists(Contact contact);
}

Lets assume we also have a contact service that implements the contact repository like so:

public class ContactService
{
    IContactRepository repository;

    public ContactService() : this(new ContactRepository())
    {
    }

    public ContactService(IContactRepository repository)
    {
        this.repository = repository;
    }

    public Contact Add(Contact contact)
    {
        if (!repository.Exists(contact))
        {
            return repository.Add(contact);    
        }
        return null;
    }
}

Now I used to write the tests like this:

[TestMethod]
public void AddContactContactDoesNotExistReturnsNewContact()
{
    var mockRepository = new Mock<IContactRepository>();
    mockRepository.Setup(x => x.Exists(It.IsAny<Contact>())).Returns(false);
    mockRepository.Setup(x => x.Add(It.IsAny<Contact>())).Returns(new Contact() { Id = 1 });
    var contactService = new ContactService(mockRepository.Object);

    var result = contactService.Add(new Contact() { Name = "Test" }) as Contact;

    Assert.IsNotNull(result, "Should have returned a contact object");
    Assert.AreEqual(1, result.Id);
}

Notice how I setup the mock repository expectations prior to assigning the mock repository to the constructor of the contact service. For some reason I always though you had to define your expectations prior to assigning the mock object to its dependents.  As it turns out this is not required.  Look at the following code and notice how the setup of the expectations comes after the mock repository has been assigned to the contact service.

[TestMethod]
public void AddContactContactDoesNotExistReturnsNewContact()
{
    var mockRepository = new Mock<IContactRepository>();
    var contactService = new ContactService(mockRepository.Object);
    mockRepository.Setup(x => x.Exists(It.IsAny<Contact>())).Returns(false);
    mockRepository.Setup(x => x.Add(It.IsAny<Contact>())).Returns(new Contact() { Id = 1 });
    
    var result = contactService.Add(new Contact() { Name = "Test" }) as Contact;

    Assert.IsNotNull(result, "Should have returned a contact object");
    Assert.AreEqual(1, result.Id);
}

Knowing that there is no specific order in regards to assigning the expectations to your mock object and assigning the mock object to its dependent object can go a long way in making your code more readable.