Looking at a personal project I’m doing at the moment I see that in terms of lines of code some of my test projects are significantly larger (up to 2.5 times in this system) than the projects they are testing. This seems like a large amount of overhead but a less superficial analysis shows that this really isn’t a negative.

Looking at the code itself it becomes apparent that the test code is significantly more straightforward that the code it tests. My test code contains no conditional statements and will have only a single path of execution. Each test is small and tests a single behaviour, which means that testing many functions requires many tests. This means that the test suite is simple and easy to write and maintain (excluding the intrinsic difficultly of the problem at hand). Many very specific tests leads to a test suite that makes it easier to highlight the errors in the code as the failure of a test will be due to a single failed assertion.

In contrast the code under test will generally contain multiple paths of execution (though ideally as few as practical). In order to test all the necessary scenarios it will be necessary to execute the code multiple times. This will inevitably result in more test code but will have a smaller impact on overall test complexity due to low complexity of each test method if you write small, focused tests.

It is also worth considering that tests represent validation of the alternate paths through the code. If you don’t have these tests (say you only test the happy case, ignoring failure cases) then you need to validate the cases manually or not test the code paths at all. The first option is a waste of effort, the second is unacceptable in professional software development.