The Art of Unit Testing: Takeaways06 Mar 2020 #books
This is THE book to learn how to write unit tests. It starts from the definition of a unit test to how to implement them at your organization. It covers extensively the subject.
“The Art of Unit Testing” teaches to treat unit tests with the same attention and care we treat production code. For example, instead of only having code reviews, we should have test reviews.
These are some of the main ideas from “The Art Of Unit Testing”.
- Write trustworthy tests
- Have a unit test project per project and a test class per class
- Keep a set of always-passing unit tests
- Use “UnitOfWork_Scenario_ExpectedBehaviour” for your test names
- Use builders instead of SetUp methods
Write trustworthy tests. A test is trustworthy if you don’t have to debug it to make sure it passes.
To write trustworthy tests, avoid any logic in your tests. If you have conditionals and loops in your tests, you have logic in them.
You can find logic in helper methods, fakes and assert statements. Avoid logic in the assert statements, use hardcoded values instead.
Tests with logic are hard to read and to replicate. A unit test should consist of method calls and assert statements.
Organization of your tests
Have a unit test project per project and a test class per class. You should easily find tests for your classes and methods.
Create separate projects for your unit and integration tests. Add the suffix “UnitTests” and “IntegrationTests” accordingly. For a project
Library, name your tests projects
Create tests inside a file with the same name as the tested code adding the suffix “Tests”. For
MyClass, your tests should be inside
MyClassTests. Also, you can group features in separate files adding the name of the feature as suffix. For example,
Safe green zone
Keep a set of always-passing unit tests. You will need some configurations for your integration tests: a database connection, environment variables or some files in a folder. Integration tests will fail if those configurations aren’t in place. So, developers could ignore some failing tests, and real issues, because of those missing configurations.
Therefore, separate your unit tests from your integration tests. Put them in different projects. This way, you will distinguish between a missing setup and an actual problem with your code.
A failing test should mean a real problem, not a false positive.
Use UnitOfWork_Scenario_ExpectedBehaviour for your test names. You can read it as follow: when calling “UnitOfWork” with “Scenario”, then it “ExpectedBehaviour”.
In this naming convention, a Unit of Work is any logic exposed through public methods that returns value, changes the state of the system or makes an external invocation.
With this naming convention is clear the logic under test, the inputs and the expected result. You will end up with long test names, but it’s OK to have long test names for the sake of readability.
Builders vs SetUp methods
Use builders instead of SetUp methods. Tests should be isolated from other tests. Sometimes, SetUp methods create shared state among your tests. You will find tests that passes in isolation but don’t pass alongside other tests and tests that need to be run many times to pass.
Often, SetUp methods end up with initialization for only some tests. Tests should create their own world. Initialize what’s needed inside every test using builders.
Voilà! These are my main takeaways. Unit testing is a broad subject. The Art of Unit Testing cover almost all you need to know about it. The main lesson from this book is to write readable, maintainable and trustworthy tests. Remember the next person reading your tests will be you.
“Your tests are your safety net, so do not let them rot.”
If you’re new to unit testing, start reading my Unit Testing 101. You will write your first unit test in C# with MSTest.