Unit Testing--A Summary
Unit testing is the process of writing code that tests other code at the smallest possible level.
So unit tests must be code.
This makes sense when you consider that the suite of tests must be run frequently. If we dedicated a person to running an entire suite of tests every time we made a change, we’d be wasting valuable time to do something that can – and must – be automated.
How Small Is A Unit of Code?
The smallest possible level is a topic of quite a bit of debate and discussion. My definition is based on years of unit testing experience. I recommend that you use your best judgement to determine the “smallest possible level” and that your definition not be set in stone. There are some guidelines you can follow to determine the smallest possible level at any given time.
What About The Design Of Your Program?
First, whenever possible don’t change the design of your program to facilitate testing.
For example, if you’re using a language with access modifiers (public, private, etc.) you shouldn’t make a method public just for testing. If the method should be private, keep it private and test it as part of a method that calls it. This can get tricky so there are exceptions, which is why we say “whenever possible” on this one.
If your code can be called by more than one calling method you’d want to make sure your code is fully tested in isolation. In this case the “unit” being tested is the individual method.
If your code can only ever be called by one other method – say for example you’ve a large, complex method into two smaller, easier to read methods – you wouldn’t necessarily need to test each of the smaller methods individually. You could test them together, in which case the “unit” being tested is the combination of the two methods.
You may have a situation where an entire class works together and fully encapsulates some feature. If the whole class works together, and always only works together, the whole class would be the “unit” to test.
"Everything is going to be connected to cloud and data... All of this will be mediated by software." – Satya Nadella
Don't Make It Overly Complicated
The final piece of guidance on the topic of the “smallest possible level” is that you don’t want to have tests that are more complex than your original code. Unit tests should make our code better and easier to understand, not harder.
When our unit tests are repetitive or redundant it’s very difficult to introduce a new developer to the code base and the tests stop acting like documentation of the software. Test thoroughly, but try to not to duplicate.
How To Document Code Through Tests
We’ve said that our tests should document our software, but we haven’t really described how to do that. The easiest way is to use descriptive names when you create each unit test. Descriptive test names – like descriptive function names in our live software – allow another developer to simply read the name of the test and have an understanding of what is being tested. Some organizations prefer to use very long names to thoroughly describe the inputs and output of each test and also describe what else the test is checking. We recommend adhering to the following guidelines for naming tests:
Decide at either an organizational level (company-wide) or a codebase level (project-wide) what naming conventions will be used on all tests
Use longer names that clearly describe what each test is checking. This can be tricky as you test functions and systems with large inputs and complex outputs, but it is better to have long names that are too descriptive than short names that don’t provide enough information
Name tests in such a way that a non-technical person can read the name of the test and have a general idea of what should be happening
Whenever possible, correlate a test with an acceptance criterion
The final piece of the documentation puzzle is to always test only one item with each test. Although it may seem like extra work to repeatedly setup what seems like the same test each time, the benefits of documentation are worth it in the long run.
Andrew Webster is a software extraordinaire who loves to write code that is clean, testable, and stable. He is a Certified Scrum Master, was a Co-Founder of a tech startup, and worked for one of the largest software consulting companies. You can find him on LinkedIn here.