views:

51

answers:

1

After reading the first 7 chapters of Pro ASP.NET MVC Framework -a very recommended read, i'd say. Throughout my reading, the author -Steve Sanderson, touched on some TDD practices a lot. Now my question is:
Steve used to perform his unit tests against the controllers themselves, an example of the book:

[Test]
    public void List_Includes_All_Products_When_Category_IsNull() {
        //Arrange: 
        IProductsRepository repository = MockProductsRepository(
            new Product { Name = "First Product", Category= "Cat11"}, 
            new Product { Name = "SecondProduct", Category = "Cat22" } 
        );
        ProductsController controller = new ProductsController(repository);
        controller.PageSize = 10;

        //Act: 
        var result = controller.List(null, 1);

        //Assert: 
        Assert.IsNotNull(result, "Didn't render view!");
        var model = controller.ViewData.Model as IList<Product>;
        Assert.AreEqual(2, model.Count, "Got wrong number of products!");
        Assert.AreEqual(model[0].Name, "First Product", "Not the expected first item.");
        Assert.AreEqual(model[1].Name, "SecondProduct", "Not the expected second item.");           
    }

I understand why Steve is testing this, obviously he needs to check his logic against the ViewData flags he set, that's why he needs to call the List controller action, my question is, Is that enough? I mean, shouldn't one test his Model objects first? Steve is using LINQ2SQL as his ORM tool, and he pretty much isn't using anything outside LINQ functionality, I mean the example only selects data, and updates by calling the LINQ built in methods; no business validation. On my real app, there is a lot of business validations that should be made, is it going to be enough (or rather easier) for me to start testing on the controller level, ignoring my Model classes (because I don't think it's a good idea)?
Waiting for your ideas Gus!

+1  A: 

I think you'll want to have separate tests for the business-logic, in addition to controller tests.

I'm arranging my controller tests just like Steve. Basically, given the condition, does my controller contain the expected View Data? That's it. No asserts on the inner details of the data or any other business-logic - that stuff in contained in separate tests.

Following your example, I'd keep that in your Controller tests, and lets say you had some business logic preventing negative prices, you might have a separate test for things like "Product_discount_does_not_result_in_negative_price()" which is de-coupled from the web context and controller. Let's say within your Product class you have a rule that makes it's price minimum a $1 even if some so-called discount is actually more than the actual default price: (a horrible example, sorry!)

[Test]
Product_discount_does_not_result_in_negative_price() {
    Product p = new Product {price = 5, discount = 10};
    Assert.IsTrue(p.price == 1); //expecting the price Get() to return 1 in this case
}

I think the problem you will run into if you kept the tests at the controller level, it will require to create tests for and implement the controllers before you are ready to do so.

Kurt Schindler
That's what I've end up doing. Thanks Kurt. Accepted!
Galilyou