Unit Tests Everywhere
June 30th 2008Recently Ive been able to extend my unit test code coverage as Ive been introducing more features into our code base. I know this is something that shouldalwaysbe done, but for whatever reason, thats not the case. What Ive come to notice is our current method of organizing our unit test makes adding new features and test for new features awkward.
Currently our unit tests align perfectly with the class they test. So for example, if we have a class:
namespace MyCompany.Domain{
public class Foo{}
}
We have, or should have, a test fixture in a separate assembly that looks like this:
using MyCompany.Domain;
using NUnit.Framework;
namespace MyCompany.Domain.Tests{
[TestFixture]
public class FooTests{}
}
This is probably a pretty typical strategy for organization. It is intuitive where to find tests for a type. Were Im loosing my taste for this method is as the solution grows to several assemblies or layers, adding new unit tests for a specific feature becomes a scattered mess of changes. If I need to add a new field, I add new tests in theUI.Tests, theDomain.Tests, Repository.Tests, Core.Tests, etc. Makes sense though right? You have to pass that new field through all the layers. Im ok with the number of tests I need to write, but I dont like having to go to eight different places to run them when I want to test my feature. It would be nice to align them them to the feature, or tag them in such a way I could find them easily. Itcould be that we are over layered and that is the real problem. We could be anonion.
Shrek: Example? Okay, er... ogres... are... like onions. Donkey: [sniffs onion] They stink? Shrek: Yes...NO! Donkey: Or they make you cry. Shrek: No! Donkey: Oh, you leave them out in the sun and they turn brown and start sproutin' little white hairs.
We are definitely an onion.or an ogre, but thats a whole different analogy.
There is a nicearticle in CoDe Magazine by Scott Bellwarethat talks about BDD. Most of it I didnt see as valuable to my every day activities until he started talking aboutSpecUnit .Net. It was, in theory, what Ive been looking for. Align my tests with my features/defects/requirements / whatever. SpecUnit .Net does some nice human readable report generation that I dont need, but why would I need a new tool when I could just categorize my tests in folders that line up with my real world problems.
That gets me close, but there is no way to run the entire category without using the command line. Still doable, but not as nice as ReSharpers unit test runner. It would be nice to get aRun all tests in this categoryfrom the context menu, but Im not sure if that would be easy to do across the different frameworks. Again it would be nice to save my unit test session so I dont loose it every time I close the IDE.
While were dreaming, Maybe we could invert the relationship and make the class under test and attribute and the tests themselves could align directly with the requirements. Something like this for example:
[Test][TypeUnderTest(typeof(Foo))] public void Correctly_Calculates_Bar(){
//...
}
Or we could even get fancy with generics:
[Test<Foo>]
public void Correctly_Calculates_Bar(){
//...
}
The IDE, ReSharper or someone could let me run all the tests for Foo if I wanted.
After Joshs comments I thought I would add a couple screen shots of using the Category attribute to group the tests as needed. You can apply the Category attribute to the method or to the TestFixture.
[TestFixture]
public class MyClassTests {
[Category("Add the ability to do work")]
[Test] public void DoWork_WithNoArgs_DoesWork(){ }
[Category("Add the ability to do additional work ")]
[Category("Add the ability to do work")]
[Test]
public void DoWork_WithAllArgs_DoesWork() { }
}
You can select Categories from the unit test runnersGroup by:combo box.
It then will group your tests by their category. I did find the UI a bit buggy. At first it wasnt applying the grouping, but after a couple attempts they started to show up.
Thanks again Josh. That will keep me content for the time being. Now if I could only inspect the entire solution for tests in the category I wouldreallyhappy.