views:

807

answers:

2

I was wondering the best practice for unit-testing controller actions that utilize model binding.

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult AddProduct(Product product)
{
}

I was wondering how you invoke the controller's method for unit testing. If you try something like this...

public void Catalog_AddProduct()
{
    CatalogController controller = new CatalogController();
    // some mocking for controller context, setting form values etc...
    controller.AddProduct(// ?);
}

Some might suggest removing Product as a parameter but, I also have another AddProduct controller action that is used for just HTTP-Gets. The only solution I could think of is maybe accepting a namevalue collection (form data) and just using UpdateModel/TryUpdateModel.

I also want to test the model binding itself is working properly so I'd like to put the responsibility of creating the new product to the model binder.

+3  A: 

I'm not sure I understand the problem, why can't you just do this:

[TestMethod()]
public void AddProductTest()
{
    CatalogController target = new CatalogController(/*testing variables*/);
    target.AddProduct(new Product { /* product details for testing */ });

    // Test the results
}

Though I think perhaps I'm not understanding the problem. Using the form post variables is a good approach however, this will work really well when you need to do edits of the product and after a while you might find it's much easier to have all your actions take the form post variables and update your model. One thing worth pointing out with the TryUpdateModel and UpdateModel is that we have run into a bug with the Entity Framework, if you try to update an entitiy framework model that is complex it can sometimes throw exceptions. But it's really easy to write your own model updater as we've done.

EDIT:

I'm not sure you'll be able to, or that you need to, test the model binding itself. The model binding is part of the MVC framework and outside the scope of the test for the controller, I wouldn't concern myself with it and assume that it will work within the context of your test.

If you really need to test the model binding, the only way that I know is to pass in the form post variables and then use the TryUpdateModel method.

Odd
I'm sorry, I wasn't clear. I thought of another sentence I forgot to append to the end but I didn't. Editing....
Chad Moran
Ahh I see. Well using the form post variables will help you test the model binder.... I'll edit my post.
Odd
I think I'll follow your advice and keep the scope specific. Thanks!
Chad Moran
You only need to test a custom (derived from DefaultModelBinder or implementing IModelBinder) model binder
Matt Hinze
+1  A: 

Now you just provided a ValueProvider to the controller.

Scott Hanselman