Taxonomy of Tests: Unit Tests
At the most granular level is the unit test. Unit tests are written by developers to verify, on in Test Driven Development specify, the functionality of a very small piece of code to the satisfaction of the developer. Usually a unit test works on one class or a small cluster of classes at a time. One of the key attributes of a unit test is the ability to test a small unit in isolation. We want to prove that the unit of code itself is working without corruption or interference from other classes.
Purposely designing code in order to create isolated unit tests is part of a successful Test Driven Development effort. Mocks and stubs are an invaluable tool to create the isolation. Some people insist that all external dependencies (databases, Active Directory, web services, etc.) be mocked out in unit tests. My best advice is to consciously quarantine inconvenient things behind gateways with an abstracted interface. Use Inversion of Control to minimize dependencies from the majority of your .NET code to these gateways. When you can't eliminate a dependency, use Dependency Injection to provide a mechanism to replace the real thing with a mock or a stub. I have had very positive (well, mostly) experience with the Model-View-Presenter (MVP) pattern described by Martin Fowler as a strategy to maximize the testability of user interface code.
Unfortunately, some units of code only exist to manipulate the database or interact with infrastructure services like messaging. Not to mention that you still have to unit test the UI screens. MVP is not enough in and of itself to guarantee a properly functioning user interface (trust me on this one). You can either marginalize this code by not writing tests and hope for the best (or let the acceptance tests take care of it), or bite the bullet and write a battery of tests that are connected. My advice is to put some ketchup on the bullet and just do it.
I do prefer to separate connected and non-connected unit tests into separate test fixture assemblies. I generally lean on only the non-connected tests during refactoring or new development. I do think it is absolutely necessary to run the integrated unit tests in both your check-in procedure and the automated build.
There is a school of thought that says if you really unit test well enough against the mocks, integrated testing is unnecessary. The NEO project is the best attempt I've seen anybody use to actually approach this ideal. I still think this philosophy is unattainable and possibly dangerous.
I've been in some heated arguments on the merits of mocking ADO.NET when testing custom data access classes. I mostly vote no to mocking ADO.NET. In this case, the unit of valuable work is manipulating the data in the database. Who cares if the code sets the “expected” parameter values when the real stored procedure has been changed in the database behind your back? In this case, the effort to value ratio is all wrong. Of course, when you’re a consultant onsite at the client you work according to their goofy development standards and politely say “Thank you sir, may I have another?”
Next up, Acceptance tests...

2 Comments:
Yay! A pragmatic perspective. No absolute religious fanaticism here. I commend you.
Darrell
http://codebetter.com/blogs/darrell.norton/
Thanks for the comment Darrell. I don't play very well with XP purists anyway.
Post a Comment
<< Home