Unit Testing MVC Controllers

2020-05-26 16:40发布

问题:

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.

回答1:

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?



回答2:

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 = "mail@test.com"
    };

    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);
}