Wednesday, March 03, 2010

TDD/Mocks with Model-View-Presenter compared to with ASP.NET MVC

The last couple of months I've been learning mocks with Model-View-Presenter scenarios, and most recently, applying that to the TDD katas. This was always meant to be a precursor to applying the same concepts to ASP.NET MVC.

In the fall, I worked through the SportsStore demo for ASP.NET MVC in [Sandersen], and over my recent 2 weeks holidays I reviewed Sandersen as well as starting to read [Palermo], who also recommends the concept of a "Presentation" layer that represents a flattened view of the Model for simpler implementation within the View tags.

I am now starting to apply that knowledge by creating a TDD kata that starts (as always) with the domain, but then introduces controllers that originate purely within each test. Only then, as their requirement in the test leads to their generation by Resharper, are they refactored out into their own class files, and moved over into the Mvc project where the real Mvc hooks are added into the controller (a using statement for System.Mvc, inheritance from the base Controller class.)

The goal here is have true test by design (and generation by usage) in ASP.NET MVC, just as I did previously with the Model-View-Presenter scenarios.

The main difference I am seeing is that instead of mocking both the repository and the view, that I am mocking the repository only, since the View is managed by the ASP.NET MVC framework. Therefore, I am primarily concerned with asserts against the ViewData.Model, to make sure that it is the expected domain layer (or flattened presentation layer) object.

I'll be releasing a full TDD kata example in the next few days, but for now, here is an example of one of the tests:

InvoiceControllerTests.cs

[Test]
public void FindInvoice_InvoiceIdInput_ReturnsFlattenedInvoice()
{
    const string invoiceNumber = "1234";
    var invoice = new Invoice(invoiceNumber);
    Expect.Call(_mockInvoiceRepository.FindByInvoiceNumber(invoiceNumber)).Return(invoice);

    _mockRepository.ReplayAll();

    var invoiceController = new InvoiceController(_mockInvoiceRepository);
    var viewResult = (ViewResult) invoiceController.FindInvoiceByInvoiceNumber(invoiceNumber);

    var flattenedInvoice = (FlattenedInvoice) viewResult.ViewData.Model;

    Assert.AreSame(invoice, flattenedInvoice.Invoice);
}

No comments: