Question

I am using the MVP design pattern to build my application's user interface. MVP starts with a model class and a view interface. Whenever I create a new model, I write unit tests for it, using Moq to mock the view interface implementation. This works great.

When I write the actual views, I write unit tests for them too. These unit tests are harder to write. I've developed a technique for writing some of them. The technique is this: I copy the model tests, replace the mock implementation with the actual implementation, and remove all asserts.

The result is an easy-to-create, but very limited, set of tests. All they do is affirm that the view doesn't crash when the model is setup and put through its paces; they do not test user interaction nor the state of the view. Nevertheless, I've found that tests written using this technique expose almost all of my UI coding errors. Accordingly, I've made this technique standard practice for my team.

My questions:

  • Does this technique correspond to any known coding practice or pitfall? I'm making this up as I go, but I'd prefer to follow standards of practice.

  • Is there an elegant way to reuse the model unit tests as view unit tests? Currently, I'm repeating a lot of code in the different tests, and that rankles, but I haven't found a better approach.

-Cyro

PS: I've asked the question specifically about MVP, but I suspect that it applies whenever there is a close relationship between a class and an interface, and both require testing.

Was it helpful?

Solution

This question is a little confusing because in an MVP pattern the model and view don't always interface with one another, but I'll assume in this case that they do and that there is some kind of data binding going on. Also it sounds like the model has a dependency on the view, rather than vice versa.

That being said, to answer the first question, it would appear that what you're actually doing in the way you're writing the View tests is to produce an integration test, i.e. testing the functionality of multiple parts of the system working together. That's useful, as you've found, in highlighting issues. What you're missing out on are two things:

  1. Conditions that specifically test the limits and edge cases that the view is programmed to deal with.
  2. Whether the view behaves as expected - showing values in the right places, having functioning buttons, links, etc.

You should consider a UI testing technology, optionally in combination with mocking out the model and presenter. You haven't mentioned what type of UI you're producing, but there are options for both web and windows. For the latter (and to some degree the former), Coded UI Tests can be useful. For web there is Selenium, WatiN, or a Coded Web Test.

To answer your second question, I have had experience doing similarly as I have found it useful to reuse the same test code for testing code with and without Entity Framework mocked out. In order to achieve this, it's almost never necessary to repeat code. There are some standard techniques you could use:

  1. Inheritance. Have your common code in a base class for both test classes. Depending on the capability of NUnit and your test runner, it may or may not be possible to have the public test methods on the base class. With both MSTest and XUnit I've ended up repeating the test methods on the most derived class and having protected methods containing the real bulk of the test. The most derived classes are responsible for providing either mocked or real dependencies to the test cases in the base class.
  2. Similarly to (1) in that the common code is in a different class, just not a derived class. Given that inheritance often ends up leaving code in a muddle, it's probably better to default to using a derived class.
  3. T4 templates could be used to write the tests and generate them into two different classes with different dependencies in each class - mocked or real.

I hope there's something in all of the above to help you test more effectively and efficiently! Best of luck.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top