Wednesday, January 30, 2008

Unit Testing: MVC

So I've talked about what MVC is and looked at MVC in Rich Client Applications.

In those posts I mentioned that MVC was pretty helpful when it comes to unit testing. This is because, as I pointed out in Unit Testing and TDD, you can't test GUIs. Of course, you can if you really set your mind to it... But at this point I'm not convinced its worth the effort.

So how does MVC help us Unit Test? Well, once you have a controller that manipulates a view, you can mock out the view and unit test the controller. So MVC gave us something in our GUI layer to test!

Here's an example. Suppose you're creating an interface in which there are three combo boxes, each one is dependent on the one before it. So, when you select a value in the first, the second one gets populated with certain data. When you select a value in the second, the third one gets populated with certain data. Change the first one, the second one loses its value, gets filled with different data, and the third one loses its value and its data is cleared. Pretty simple little UI and not all that uncommon.

So, the view is simple, it's three combo boxes. Lets ignore data binding to keep this example even simpler. So what does our view's interface look like?
  • ClearComboBox2Value
  • ClearComboBox3Value
  • SetComboBox2DataSource( data )
  • SetComboBox3DataSource( data )
Now our controller can cause the view to change state by calling the methods on the view. How does the controller know when values have been changed on the view? This could be done in two ways.
  1. Add events to the view that fire when the values of ComboBox1 and ComboBox2 change
  2. Simply put methods on the controller to indicate the values have changed and have the view call the controller
Personally I prefer the second approach. This approach makes it easier to test and easier to read the view's code. Also, it doesn't violate the dependency chain of MVC because the controller still doesn't depend directly on the view. The view depends on the controller, but that's OK. If you need to provide different controllers to the same view you can do this with Dependency Injection. So, if you're willing, lets go with the second approach.

Now we have a view and a controller. Can we unit test the view? You can, but I'm not. Can we unit test the controller? YES!

Why does this matter? Well, the controller now contains the actual behavioral logic of the form. By testing the controller we guarantee that that logic is correct. Now we just have to test that the view updates its state appropriately. You could do this manually by clicking around, or you could use a visual scripting framework to click around for you, or you could write code to click for you... I'm still just doing it manually.

Again, no silver bullet, but we're 80-90% there (depending on how complicated the view is).

The post on MVC in Windows Applications ended without an answer. However I think this post clarifies that the benefits of unit testing a controller likely out weigh the complexity that comes from MVC.

Have you tried it? What do you think? Why not leave a comment? Josh always does! Is he really that much better than you?

1 comment:

  1. Ill be honest i didn't read this post (yet) but i did see the last line and I completely support more discussion on this blog. Kevin knows he has readers so some of y'all need to post some feedback. We don't completely destroy you with our obviously superior intellect ;-)