Blog Cover

F.I.R.S.T. principles of testing

Author profile image
Aitor Alonso

Feb 25, 2024

3 min read

Today, I want to do a brief introduction to the F.I.R.S.T principles of testing, similar to what I did in the article about the S.O.L.I.D principles of software design.

The F.I.R.S.T principles serve as a foundational framework for effective code testing. These principles, which stand for Fast, Isolated, Repeatable, Self-validating, and Thorough, guide developers in creating robust and reliable tests to ensure the quality and integrity of their code.

Let's take a closer look at each of the F.I.R.S.T principles:

Fast

One key tenet of the F.I.R.S.T principles is speed. Developers are encouraged to run unit tests swiftly and effortlessly throughout the development process. Regardless of the number of unit tests in place, they should execute rapidly, providing prompt feedback on the code's correctness.

If tests take too long to run, developers may be less inclined to run them frequently, or even adding new ones, leading to a decrease in the overall quality of the codebase. Fast tests are essential for maintaining a productive and efficient development workflow, and a robust and reliable codebase.

Isolated

The principle of isolation emphasizes the independence of each unit test. Tests should not rely on external factors or be influenced by the outcomes of other tests.

It's a good practice to follow the 3 A’s of testing: Arrange, Act, Assert (also known as Given, When, Then by Martin Fowler), which defines a structure that helps maintain a clear and autonomous testing environment.

Basically, the test should first arrange the necessary preconditions and inputs, then act on the object or method under test, and finally assert that the expected results have occurred.

A unit test should only assert one logical outcome (test one single thing). Multiple asserts can be part of this logical outcome, as long as they all act on the state of the same object.

Repeatable

Reproducibility is crucial in the F.I.R.S.T methodology. Tests should be consistent and deterministic, producing the same results regardless of the environment in which they are executed. Each test should establish its own data context, reducing reliance on external variables.

Sadly, we all know about the flaky tests that sometimes pass and sometimes fail, and how they can be a nightmare to deal with. Sometimes your CI tests jobs fails, blocks your deploy, and just rerunning the same job without changing anything makes it pass. The F.I.R.S.T principles advocate for the elimination of flaky tests, as they can erode confidence in the testing process and the codebase as a whole.

Self-validating

Manual verification of test outcomes should be unnecessary. Tests should inherently indicate success or failure, facilitating quick identification of issues during the development process.

Thorough

Exhaustive testing is a fundamental aspect of the F.I.R.S.T principles. Developers are encouraged to cover all possible scenarios, including edge cases and potential failure points. Testing should extend beyond typical use cases and happy paths to encompass illegal arguments, security considerations, and the impact of large input values. Try to cover all the branches of your code and all possible scenarios.

Summarizing

In conclusion, the F.I.R.S.T principles provide a structured approach to code testing, emphasizing speed, independence, repeatability, self-validation, and thoroughness. By incorporating these principles into the testing process, developers can enhance the readability and maintainability of their tests, and also the reliability and maintainability of their code, ultimately contributing to the delivery of high-quality software.


I hope my article has helped you, or at least, that you have enjoyed reading it. I do this for fun and I don't need money to keep the blog running. However, if you'd like to show your gratitude, you can pay for my next coffee(s) with a one-time donation of just $1.00. Thank you!