unit-testingcode-organization

How do you organise your MVC controller tests?


I'm looking for tidy suggestions on how people organise their controller tests.

For example, take the "add" functionality of my "Address" controller,

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Add()
{
    var editAddress = new DTOEditAddress();
    editAddress.Address = new Address();
    editAddress.Countries = countryService.GetCountries();

    return View("Add", editAddress);
}

[RequireRole(Role = Role.Write)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(FormCollection form)
{
    // save code here
}

I might have a fixture called "when_adding_an_address", however there are two actions i need to test under this title...

I don't want to call both actions in my Act() method in my fixture, so I divide the fixture in half, but then how do I name it?

"When_adding_an_address_GET" and "When_adding_an_address_POST"?

things just seems to be getting messy, quickly.

Also, how do you deal with stateless/setupless assertions for controllers, and how do you arrange these wrt the above? for example:

[Test]
public void the_requesting_user_must_have_write_permissions_to_POST()
{
    Assert.IsTrue(this.SubjectUnderTest.ActionIsProtectedByRole(c => c.Add(null), Role.Write));
}

This is custom code i know, but you should get the idea, it simply checks that a filter attribute is present on the method. The point is it doesnt require any Arrange() or Act().

Any tips welcome!

Thanks


Solution

  • In my opinion you should forget about naming your tests after the methods you're testing. In fact testing a single method is a strange concept. You should be testing a single thing a client will do with your code. So for example if you can hit add with a POST and a GET you should write two tests like you suggested. If you want to see what happens in a certain exceptional case you should write another test.

    I usually pick names that tell a maintainer what he needs to know in Java:

    @Test public void shouldRedirectToGetWhenPostingToAdd(){
        //...
    }
    

    You can do this in any language and pick any *DD naming convention if you like, but the point is that the test name should convey the expectations and the scenario. You will get very small test this way and I consider this a good thing.