What I Learned About Writing Unit Tests: My First Tests
Over the last 4 years, I embraced the idea of writing unit tests for my software. Most of what I’ve written during these years has been software frameworks, with very high reliability and stability guarantees and explicit needs for backwards compatibility—all perfectly ripe for a good unit test suite. In the following short series of posts, I will try to share the story of what I learned from writing unit tests, and why the tests I write today are nothing like the tests I wrote 4 years ago.
The first unit tests I’ve written were taken straight from “the book”. I would take a class, strip it of all its dependencies and test every method and every constructor and every possible feature of it. These tests would be somewhat similar to the following:
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void LoggingFramework_LogCtorWithNullString_Throws()
{
new Log(null);
}
I got very high code coverage with this kind of tests, but I couldn’t stop thinking that they didn’t bring much value to my software. I mean, yes, it’s important that the Log constructor throws a specific exception when passed a null string, and it’s even more important because it’s written in the public API documentation that I ship with the framework. But writing hundreds of such tests by hand and then saying that I have 100% code coverage didn’t convince me that my framework worked properly.
Specifically, even though it might belong to the QA department, when designing a framework it’s critical to test the APIs of that framework in a realistic way. It must be possible to design a unit test (not a system test, not an integration test) that tests the API and not just a single constructor at a time.