Tag Archives: unit testing

MVC: the view model

The ComicShop application we’ve presented so far has been quite basic, in that it does nothing more than allow the user to store comics in a local database, and display a list of these comics on the home page. In the process of creating the application, though, we’ve shown the division of labour between the model (where the data are stored and manipulated), the controller (which handles requests from the user and decides which view to display), and the view (which creates the actual HTML that is sent back to the browser).

You might think that, having covered all three components for which MVC is named, we’re finished with the basics. However, there is another logical component that forms part of the design when the application becomes anything more than very simple. This is the view model. (The view model occupies a more central position in another design system known as MVVM (thanks Stuart!), but we’ll leave a discussion of that until later.)

To illustrate the need for a view model (and to explain what it is), suppose we wanted to add a web page that displayed a summary of the comics in the database by listing each unique title followed by the number of comics of that title in the database. Ultimately, we’d like to display this information as a table in HTML, where each row in the table consists of a string (the title) and an int (the count for that title). To obtain this information, we need to query the database and do a count of each title returned. Where should this work be done?

One option is that the controller queries the database for a complete list of comics (as it does for the page that displays the complete list), and sends this list as is to the view, leaving the view to count up the number of comics for each title and then display the results. This isn’t very efficient, since the view is being forced to do a lot of stuff that has nothing to do with the display of the page.

Another option is that the controller does the calculations itself and then packages up the results and sends them to the view for display. That seems a little better, since at least the view is being cluttered with calculations. However, it isn’t really the job of the controller either, since its job is mainly to route the page request from the user to the correct view.

The solution currently accepted as best practice is to have the controller create a view model which is then sent to the view. The view model is a mirror in C# code of the data that the view requires in order to produce the HTML. In the case of our ComicShop summary page, we’d like a list of rows for the table, where each row contains the title and count for a group of comics. We therefore create a class representing a single row in the table, which looks like this:

namespace ComicShop.Models
{
  public class ComicSummary
  {
    public string Title { get; set; }
    public int Count { get; set; }
  }
}

The idea is now to have the controller construct the view model as an IEnumerable<ComicSummary> list (that is, a collection of ComicSummary objects that implements the IEnumerable interface), and that is what gets sent to the view. This list is the view model for the view that displays the summary information. It contains only the information that the view needs, and doesn’t require the view to do any further calculation.

Where should this list be constructed? To keep the controller clean, the construction shouldn’t be done directly inside the controller. Farming the process out to a separate class also fits in with the design we adopted when implementing unit testing, since we’d like to be able to test the summary-generation code in the controller without directly accessing the database. A sensible place to put the list-building code, then, is in the classes (one for testing and one for running normally) that implement the IComicRepository interface that we designed in the post on unit testing.

When we’re extracting the information from the database, we can actually do all the calculations required using LINQ. Here’s the method in the ComicRepository class:

    public ComicContext database = new ComicContext("ComicContextDb");
    public IEnumerable<ComicSummary> GetSummaries()
    {
      var summaries = database.ComicBooks.Select(book => book).OrderBy(book => book.Title).
        GroupBy(comic => comic.Title,
        (title, titleGroup) => new ComicSummary
        {
          Title = title,
          Count = titleGroup.Count()
        }
        );
      return  summaries;
    }

The first line in the method is the LINQ code that selects all the comics, orders them by title, and then applies the GroupBy() method to sort them into groups where the key to each group is the Title field. The second argument to GroupBy() is a function which takes two parameters: the first is the title of the comic, and the second (titleGroup) is the group of comics with that title. We then construct a ComicSummary object containing the title and the count of comics in that group. The final returned object is the required IEnumerable<ComicSummary> list.

Back in the HomeController class, we add an action for the Summary page:

    public ViewResult Summary()
    {
      IEnumerable<ComicSummary> summaries = comicRepository.GetSummaries();
      return View(summaries);
    }

(The comicRepository object is initialized in the constructor as before.) The controller code is still very clean, since the work of building the view model is done in ComicRepository.

Finally, the view for the Summary page is also very simple:

@using ComicShop.Models
@model IEnumerable<ComicSummary>

<div>
    <h2>Comic summary</h2>
    <table>
        <tr>
            <th>Title</th>
            <th>Count</th>
        </tr>
        @foreach (var summary in Model)
        {
            <tr>
                <td>@summary.Title</td>
                <td>@summary.Count</td>
            </tr>
        }
    </table>
</div>

The model directive at the top is set to an IEnumerable<ComicSummary> data type, making this a strongly typed view. The rest of the view builds the table by iterating over the elements in the model.

Finally, we can add a GetSummaries() method to our test repository class ComicRepositoryTest. It might look something like this:

    public IEnumerable<ComicSummary> GetSummaries()
    {
      return new[]
      {
        new ComicSummary
        {
          Title = "Superman",
          Count = 3
        },
        new ComicSummary
        {
          Title = "Thor",
          Count = 12
        }
      };
    }

We manually add a couple of ComicSummary objects to a list and return it. To use this, we can add some tests to HomeControllerTests. For example, we can test that the number of entries in the table is 2:

    [TestMethod]
    public void Summary_Count()
    {
      HomeController homeController = new HomeController(
        new ComicRepositoryTest());
      var summary = homeController.Summary();
      var table = summary.Model as ICollection<ComicSummary>;
      Assert.IsTrue(table.Count == 2, "Count is {0}", table.Count);
    }

Since IEnumerable <T> doesn’t support a Count property, we’ve cast the Model field of ‘summary’ to an ICollection, which does have a Count. ICollection inherits IEnumerable, so the cast is valid providing the underlying object implements ICollection, which in this case it does.

Advertisements

Unit testing: decoupling the database

In the last post, we saw how to add a simple unit test to an MVC4 project. At the time, we noted that our ComicShop project wasn’t in the best form for unit testing, since the HomeController accessed the database (in which the comic books are stored) directly. This means that any test of HomeController required interacting with the database, so we’re not testing just the code in the controller in isolation.

Here, we’ll see how to decouple the database from the controller, and in the process, how to add in a localized test for the controller that is independent of the database.

The idea is to define a C# interface whose job it is to provide the connection to the data source. In the functioning application, this interface is implemented by a class that does connect to the database, but for testing purposes, we use another class that also implements this interface, but which provides a test set of data without referring to a database.

To design this interface, we look at the HomeController code, and note that there are, at the moment, only two methods that interact with the database: Index(), which retrieves the list of Books in the database, and the HttpPost version of Add(), which takes data off a form submitted by the user and adds this to the database. The other Add() method just displays a form in which the user enters data; no connection to the database is used here.

Our interface, then, should contain two methods which, in classes implementing the interface, are used to connect to the database in one case and to some local data source in the testing case. Here’s the definition of the interface:

using System.Collections.Generic;

namespace ComicShop.Models
{
  public interface IComicRepository
  {
    List<Book> GetComicList();
    void AddComic(Book book);
  }
}

We’ve added this interface to the Models namespace, since it deals with data storage, and classes that implement it are model classes.

We can now define a class called ComicRepository which implements IComicRepository and move the code relying on the database from HomeController to ComicRepository. This class is as follows:

using System.Collections.Generic;
using System.Linq;

namespace ComicShop.Models
{
  public class ComicRepository : IComicRepository
  {
    public ComicContext database = new ComicContext("ComicContextDb");
    public List<Book> GetComicList()
    {
      var comics = database.ComicBooks.Select(book => book).OrderBy(book => book.Title);
      return comics.ToList();
    }

    public void AddComic(Book book)
    {
      database.ComicBooks.Add(book);
      database.SaveChanges();
    }
  }
}

GetComicList() contacts the database and retrieves the list of books using the same LINQ code as we had in HomeController before. However, it converts the result to a List<Book> and returns it. There is no mention of a View, since that’s the job of the controller; this class should concern itself purely with manipulating the data.

In a similar vein, AddComic() accepts a Book and adds it to the database.

The new version of HomeController now looks like this:

using System.Web.Mvc;
using ComicShop.Models;

namespace ComicShop.Controllers
{
  public class HomeController : Controller
  {
    private IComicRepository comicRepository;

    public HomeController()
    {
      comicRepository = new ComicRepository();
    }

    public HomeController(IComicRepository comicRepository)
    {
      this.comicRepository = comicRepository;
    }

    public ViewResult Index()
    {
      var model = comicRepository.GetComicList();
      return View("IndexModel", model);
    }

    public ActionResult Add()
    {
      return View();
    }

    [HttpPost]
    public ActionResult Add(Book book)
    {
      comicRepository.AddComic(book);
      return Content("New comic added.");
    }
  }
}

All explicit references to the database have been eliminated. The interaction with the data source is done entirely through the comicRepository object.

A couple of important additions have been made: we now have two constructors in HomeController.

The argumentless constructor initializes the comicRepository object to ComicRepository, the class that accesses the database. We want this to be the default behaviour of the controller, since this is what is done when we are running the web site.

The second constructor allows us to specify the repository used by HomeController. We’ll use this constructor when we write the test class.

First, we need to define a test class that implements IComicRepository. This class should use a local data source without any reference to the database. Since the web site uses a List<Book> as its working data structure, we can use this as the test data source. We therefore define ComicRepositoryTest like this:

using System.Collections.Generic;
using ComicShop.Models;

namespace ComicShop.UnitTests.Models
{
  public class ComicRepositoryTest : IComicRepository
  {
    private List<Book> comicRepository;

    public ComicRepositoryTest()
    {
      comicRepository = new List<Book> {
        new Book {
          Title = "Incredible Hulk", Volume = 3, Issue = 134
        },
        new Book {
          Title = "Superboy", Volume = 1, Issue = 17
        }
      };
    }

    public List<Book> GetComicList()
    {
      return comicRepository;
    }

    public void AddComic(Book book)
    {
      comicRepository.Add(book);
    }
  }
}

We’ve put this class in the namespace ComicShop.UnitTests.Models (you’ll need to create a new folder in your tests project in Visual Studio), since it’s a data class. Since it implements IComicRepository, we need a ‘using ComicShop.Models’ at the top.

This class has a constuctor that initializes the List<Book> and adds a couple of Books to it. Note that although this class is in the UnitTests namespace, it’s not a TestClass itself; it’s just an auxiliary class that is used in the testing.

We then implement the two methods in IComicRepository. GetComicList() just returns the List<Book>, and AddComic() adds the Book to the List<Book>.

We can now go back to HomeControllerTests (that we started in the last post), and rewrite the tests properly. The class now looks like this:

using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ComicShop.Controllers;
using ComicShop.Models;
using ComicShop.UnitTests.Models;
using System.Web.Mvc;

namespace ComicShop.UnitTests.Controllers
{
  [TestClass]
  public class HomeControllerTests
  {
    [TestMethod]
    public void Index_ValidView()
    {
      HomeController homeController = new HomeController(
        new ComicRepositoryTest());
      var result = homeController.Index();
      Assert.IsNotNull(result);
    }

    [TestMethod]
    public void Add_AddBook()
    {
      HomeController homeController = new HomeController(
        new ComicRepositoryTest());
      homeController.Add(
        new Book
        {
          Title = "Iron Man",
          Volume = 3,
          Issue = 57,
          Publisher = "Marvel"
        }
      );
      var result = (ViewResult)homeController.Index();
      var modelList = (List<Book>)result.Model;
      Assert.IsTrue(modelList.Count == 3, "Count is {0}", modelList.Count);
    }
  }
}

Each test should be entirely self-contained, so we don’t define any class variables; we create an instance of HomeController within each TestMethod. For the tests, we pass an instance of ComicRepositoryTest to the HomeController constructor, so HomeController uses the local data source rather than the database. The Index_ValidView() test is the same test we wrote in the previous post, except this time there is no interaction with the database.

We’ve added another TestMethod to test adding a Book to the data source. Add_AddBook() calls HomeController’s Add() method with a Book that is created on the spot, rather than using data sent in by the user from a web page. We then retrieve the list of Books by calling Index() and extracting the Model field from the ViewResult. Since the list defined in ComicRepositoryTest had two Books in it and we’ve added another one, the size of the list should now be 3, so that’s what we test in the Assert.IsTrue() statement.

Some of Assert’s methods allow an optional message to be printed out if the test fails. In this case, the last two parameters sent to Assert.IsTrue() are a string and its parameter. If the Count of items in the list is not 3, we’d like to see how many items are in the list, so we print that out. You can test this feature by changing the test so it fails (by testing if Count is 4, say). To see this message, click on the failed test in Visual Studio’s Test Explorer, and the results should show up at the bottom of the panel.

We could go on and add more tests to the ComicShop project, but you should get the idea at this stage.

MVC: unit tests

Having spent all my working life in academia, I never got into the formal-testing-of-code mindset, even though I wrote some fairly hefty programs. Of course I tested my programs, but it was mainly a case of trying every possible scenario by hand and then fixing things that didn’t work.

Testing has turned into something of an industry in its own right. The more extreme testers advocate test-driven development, in which the test for a section of code is written before the code itself, and the code is then written so it passes the test.

Whatever your philosophy on testing, having a set of tests which can be run at any time at the press of a button is surely a nice idea, and Visual Studio has tools that support this form of testing. We’ll have an introductory look at how to include unit tests in an MVC4 project, using Visual Studio 2012 (version 11).

When you create an MVC4 project in VS, there is an option to create a test suite at the same time. However, if you don’t do this and opt instead for the empty project (as we’ve done up to now), it’s easy enough to add in a test project later.

One thing is worth pointing out here, though. Older versions of VS had a feature where you could right-click on a class or method in your code and add a unit test on the fly. For technical reasons, this feature has been removed in VS2012, so the only way of adding tests (as far as I can tell) is via the test project itself.

To add a test project to an existing solution, right-click on the existing solution in Solution Explorer and select Add–>New project, then click on the Visual C#–>Test node and select Unit Test Project. You’ll get a starter C# file which looks like this:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ComicShop.UnitTest
{
  [TestClass]
  public class UnitTest1
  {
    [TestMethod]
    public void TestMethod1()
    {
    }
  }
}

Note that a class used for unit testing must have the attribute TestClass, and a method must have the attribute TestMethod.

Even at this stage, we can run the test. In the Test menu, select Windows–>Test explorer, and in the Test Explorer window, click on Run All. Since there are no conditions yet that can fail, the test should pass, and you’ll see a message to this effect.

To see what happens when a test fails, insert the line Assert.IsTrue(1 > 2); in the TestMethod1 method and run the test again. The condition is clearly false, so the test will fail, and the Test Explorer tells you this, along with which test failed.

Since we’ll be testing code we’ve written in the original ComicShop project, the ComicShop.UnitTests project needs access to that code, which it doesn’t have at the moment. To rectify this, right-click on References in the ComicShop.UnitTests project and then Add reference. Expand the Solution node and under Projects, select the ComicShop project and add it.

We now have enough material to be able to add unit tests to our existing code. However, the code as it stands isn’t in quite the right form for ‘proper’ unit testing. The reason is that the controller code we wrote in earlier posts has a direct link with the database used to store the comic book data. Thus any unit test we write for a controller method will involve connecting to the database. You might think that any proper test would have to do this anyway; after all, the program connects to the database so surely any test would also have to do this.

The point is that there are really two distinct operations involved in the controller method as it stands. First, there is the connection to, and interaction with, the database. Second, there is the logic in the controlller method itself; that is, the logic that determines what the controller does with the data it gets from the database (or sends to it, if we’re adding a new comic book). We’d really like to test these two things separately.

We’ll see in the next post how to decouple the controller from the database, but for now, just to get used to writing a unit test, we can write a simple unit test with the controller code as it stands. As a reminder, here’s the code for the Index() method in the HomeController.

    private ComicContext database = new ComicContext("ComicContextDb");
    public ActionResult Index()
    {
      var comics = database.ComicBooks.Select(book => book).OrderBy(book => book.Title);
      var model = comics.ToList();
      return View("IndexModel", model);
    }

We’ll test that the ActionResult returned at the end isn’t null.

It’s a good idea to mirror the the original application’s code structure in the unit test code structure, so we’d like tests on HomeController to be in a Controllers namespace within ComicShop.UnitTests. To do this, right-click on the ComicShop.UnitTests project and select Add–>Add folder, then name this folder Controllers. Right-click on the Controllers folder and then on Add–>Unit test. Name the new test HomeControllerTests. (Do not click on Add–>Class to add the test, since the resulting class won’t be included in the tests.)

Here’s the complete class that does our simple test.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ComicShop.Controllers;
using System.Web.Mvc;

namespace ComicShop.UnitTests.Controllers
{
  [TestClass]
  public class HomeControllerTests
  {
    [TestMethod]
    public void Index_ValidView()
    {
      HomeController homeController = new HomeController();
      var result = homeController.Index();
      Assert.IsNotNull(result);
    }
  }
}

We create a HomeController object, call its Index() method and save the returned value in ‘result’. We then apply one of the static methods in the Assert class (one of the provided UnitTesting classes). As you can see from the Intellisense, there are a lot of tests in Assert. This one does just as it says: it tests if ‘result’ is null.

Before we leave this introductory post, it’s worth pointing out that any method that is to be used as a TestMethod must be void (return nothing) and have no parameters. The unit test must be completely encapsulated within the code for that method.

In order to test anything more significant than this, we should really restructure our code so that we decouple the controller from the database, but that’s a topic for the next post.