Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing MVC Controllers

A controller in my ASP.NET MVC application pre-populates form data displayed by my view according to a couple of fairly straight forward rules.

It seems like this would be a good thing to cover in my unit testing. But the only way I could see to verify the correct data is placed in the form, would be to extract the logic from the controller in what feels like an unnatural way.

Can someone suggest ways to approach this?

All the examples I've found of unit testing controllers seemed very trivial, such as verifying it returned the expected type of view. I'm not sure I even see the value in that.

like image 413
Jonathan Wood Avatar asked Dec 19 '11 14:12

Jonathan Wood


People also ask

Can you unit test controllers?

When unit testing controller logic, only the contents of a single action are tested, not the behavior of its dependencies or of the framework itself. Set up unit tests of controller actions to focus on the controller's behavior. A controller unit test avoids scenarios such as filters, routing, and model binding.

What is unit testing in MVC?

In computer programming, unit testing is a software testing method by which individual units of source code are tested to determine whether they are fit for use.

Should you write unit tests for controllers?

Controller logic can be tested using automated integration tests, separate and distinct from unit tests for individual components. -1: A unit test for a controller could be pointless.

How does MVC enable is of unit testing?

ASP.NET MVC exposes extensibility APIs that enable developers to participate in the resolution and instantiation of controllers, and which enables Dependency Injection / IoC frameworks to be cleanly integrated within this process.


2 Answers

You can test by casting the returned object to the appropriate class, instead of using their base class (which is returned by default)

For example, to test the default AccountController you'd so something like this:

var controller = new AccountController();
var result = controller.LogOn() as ViewResult;
var model = result.Model as LogOnModel;

Assert.IsTrue(model.RememberMe); // assuming you "pre-populated" enabled the checkbox

Checking if the returned object is filled with the right data does not seem "unnatural" to me, or did you meant it differently?

like image 102
Ron Sijm Avatar answered Oct 15 '22 19:10

Ron Sijm


I would agree that testing the type of view returned would be somewhat pointless. However, testing that the expected "view" was returned along with its correct data would be a valid test case IMO.

For example here is a singular edit test case for an edit controller. Note, that this example is making use of Moq and Nunit but that aside it's fairly straight forward.

Note, that that ViewResult is cast to the expected view model and the assertions are then made against the expected contact.

Test:

[Test]
public void Edit_Get_Should_Lookup_Contact_From_Repository_And_Return_Edit_View()
{
    // arrange
    var _repository = new Mock<IContactRepository>();

    var expectedContact = new Contact
    {
        First = "first",
        Last = "last",
        Email = "[email protected]"
    };

    var mockContext = new Mock<ControllerContext>();
    _repository.Setup(x => x.GetById(It.IsAny<int>())).Returns(expectedContact);

    var controller = new ContactController(_repository.Object)
    {
        ControllerContext = mockContext.Object
    };

    // act
    var result = controller.Edit(1) as ViewResult;
    var resultData = (Contact)result.ViewData.Model;

    // assert
    Assert.AreEqual("Edit", result.ViewName);
    Assert.AreEqual(expectedContact.First, resultData.First);
    Assert.AreEqual(expectedContact.Last, resultData.Last);
    Assert.AreEqual(expectedContact.Email, resultData.Email);
}

Controller:

[HttpGet]
public ActionResult Edit(int id)
{
    var contact = _repository.GetById(id);

    return View("Edit", contact);
}
like image 26
Jesse Avatar answered Oct 15 '22 19:10

Jesse