Monday, January 10, 2011

Unit tests should be in the same project as the code under test

Most of the .NET projects that I have seen with decent test coverage have the unit tests located in a separate test project. The structure of this unit test project usually reflects the structure of the project under test. Any folder and class in the project under test would also exist in the test project, but where the class has a *Tests suffix in the name.

On a project that I'm working on we also did it the same way. In the beginning it worked pretty well, keeping the two projects in sync wasn't too much hassle. But as the structure and the code was growing in size the two projects got more and more out of sync. The project under test would get new code added and it would get refactored, while the unit test project would not. Also more and more classes were lacking unit tests or the tests weren't up to date. Before this got totally out of hand I decided to find a better way to structure things. After playing around with a few different approaches I ended up with a simple solution to this problem. By simply moving the unit tests in to the same project as the code under test the problem was solved. The project under test would then have both a class A and a class ATests.

This approach has some nice benefits:
1) Easy to see if a class has any tests, just look for the ClassNameTests class.
2) Don’t have to maintain multiple structures.
3) Makes navigation between the class under test and the test class easier.
4) Signals the importance of unit tests.

But it also has some drawbacks:
1) The project needs to reference all the libraries that are required by the test code, such as mocking frameworks.
2) Changing the projects into a test project gives some overhead when compiling.
3) The compiled code/assemblies will be bigger in size. A way to solve this is to remove all the *Tests classes before compiling.

For unit tests I would recommend using this approach. When it comes to integration tests I suggest having them in a separate project as these tests are not to be run as frequent as the unit tests.