Unit Test Guidelines and Examples

Guidelines

Regardless of the language you are programming in, when it comes time to unit test, you should consider exactly what is it that should be tested.

  • Every public function or method that is longer than about 15 lines or does a lot of logic tests
  • Short functions/methods that can be verified by hand have a lower need to have a unit test for them (unless you are trying to bump your coverage numbers up).

What about private helper functions or methods? There seems to be a lot of debate by developers about this topic. Any private function/method that is critical to the operation of the code has unit tests created for it. If the test framework/language supports mocking, then mocking the private method is acceptable. Below are some thoughts on testing private functions/methods from Testing Private Methods.

If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there’s another class in there struggling to get out. When push comes to shove, however, it’s probably better to break encapsulation with working tested code that it is to have a good encapsulation of untested, non-working code."
-- Pragmatic Unit Testing

Package scoping particularly shines during unit testing. Some programmers argue that you should only test through the public API. Don’t be silly. Limiting your tests to the public API contradicts the spirit of unit testing and subjects you to unnecessary dependency pain. I prefer to isolate and limit the amount of code I test at one time, and test as close to the code as possible.
-- Bob Lee

Coverage Reports

The nightly coverage reports generated by our continuous integration server provide a good indicator of code being tested. It's also a great way to determine what additional unit tests are needed to increase coverage. A coverage report for the ununpack agent showed low line coverage for the file utils.c. Clicking on the file takes you to a line by line coverage report. The screen shot below shows a section of code that is not being exercised by the tests:

For the following example, I'll use the coverage report above to determine what additional unit tests should be written to increase unit test coverage for utils.c.

Examples from FOSSology

Looking at the code above, we can see that the current unit tests are not exercising IsExe. So, let's write a test to do that. There's an existing suite of tests called test_IsFunctions that includes tests for IsDebianSourceFile in utils.c. This would be a logical place to add a test for IsExe. Here's the test:

/**
 * @brief function IsExeFile(char *Filename)
 */
void testIsExeFile()
{
  char *Filename = "../testdata/testdata4unpack/fcitx_3.6.2-1.dsc";
  Result = IsExe(Filename, 1);
  FO_ASSERT_EQUAL(Result, 1);
}

With this added test, the IsExe function will now get exercised and thereby increase the coverage of utils.c, as shown in the screen shot below:

For more info: