Show Menu

Best practices for writing good unit tests.

About unit testing

Production code cleanl­iness cannot be greater than test code cleanl­iness.
Test code cleanl­iness mainly depends on its readab­ility.
Unit tests can be viewed as specif­ica­tions of the system.

FIRST principles

Fast : tests should be fast. If they're slow, they won't be run.
Independant : tests should not depend on each other, otherwise their result will be hard to analyze.
Repeatable : tests should be repeatable in any enviro­nnement. Their execution should not depend on the availa­bility of a specific enviro­nne­ment.
Self-Va­lid­ating : tests should either pass or fail. Evaluating their result mustn't be subjec­tive.
Timely : tests should be written just before the production code is written. If they're written after, they will be difficult to write.

Test Driven Develo­pment

Test Driven Develo­pement is a great way to write unit test in a timely manner and achieve a good mutation score.
1st rule : you may not write production code until you have written a failing unit test.
2nd rule : you may not write more of a unit test than is sufficient to fail, and not compiling is failing.
3rd rule : you may not write more production code than is sufficient to pass the currently failing test.
Obvious implem­ent­ation : just write it and see if the tests pass.
Triang­ulate : drive implem­ent­ation by using a set of several examples.

General rules

One test equals one case.
Name tests in way that shows the pattern "­Given - When - Then" (aka Act - Arrange - Assert, Build - Operate - Check, etc).
The body of test methods should clearly show the pattern "­Given - When - Then".
"Hide wires" : boiler­plate or technical code irrelevent to unders­tanding a test should be hidden.
Hide irrelevant functional data. It is noise that lowers the unders­tan­dab­ility of the test.
Abstract magic values by giving them meaningful names. It makes tests more unders­tan­dable.
Do not duplicate production logic. If the logic has a bug, it will be duplic­ated, making the test useless.
Do not use condit­ional logic. It lowers the readab­ility of the test. Split the test instead.

Test doubles

Dummy : fixed values not used by tests.
Stub : fixed values used by tests.
Fake : dynamic values used by tests.
Spy : fixed values used by test ; provides data to inspect its behavior.
Mock : fixed values used by test ; provides methods to inspect its behavior.
Only use tests doubles when necessary. Do not over use them as it will lower the readab­ility and mainta­ina­bility of the tests.
Use "­man­ually create­d" fakes most of the time. They are reusable, decouple test code from production code and discourage the use of assertions based on behavior.
Use "­dyn­ami­cally create­d" test doubles by using a framework when you need a specific behavior not reusable elsewhere.
Use "­dyn­ami­cally create­d" test doubles when you have no choice but to make assertions based on behavior.


Prefer assertions based on states over assertions based on behavior. The later are less mainta­inable as they couple test code to production code.
Use an expressive assertion framework. Assertions should be unders­table quickly.
Only make assertions regarding current case. Tests should only fail regarding their case expect­ations.
Do not aggregate assert­ions, as the cause of a failing test would be hard to spot.
Assert exceptions as they also are specif­ica­tions of the system.

Testing approaches

Use proper­ty-­based testing to spot values that don't produce expected output.
Proper­ty-­based testing and tradit­ional exampl­e-based testing are comple­mentary.
Use "­golden master testin­g" to take a snapshot of legacy code outputs before refact­oring it.
Parame­terized tests can help dealing with edge values, by using a set of values covering the edges.
When fixing a bug, start by writing a test that shows it exists, then fix the bug.


Do not rely on code coverage alone : it only shows if production code is executed by the tests.
Use mutation testing over code coverage to evaluate unit tests effect­ive­ness.
Mutation testing also helps having a minimal production code, less production code meaning less possible mutations.


Test doubles defini­tions inspired from this post by Robert C. Martin


No comments yet. Add yours below!

Add a Comment

Your Comment

Please enter your name.

    Please enter your email address

      Please enter your Comment.

          Related Cheat Sheets

          Selenium WebDriver Cheat Sheet Cheat Sheet
          Cypressio Cheat Sheet
          ISTQB Test Automation Engineering Cheat Sheet