How to write tests correctly? (Part 1)

How to write tests correctly? (Part 1)

The first part is a short article without programming language binding, which will be suitable for everyone who has questions about how to improve the quality of their tests.

Let’s discuss three basic approaches to testing something in the program:

1. Testing of observed behavior (according to the black box principle).

Of course, as developers we know what code we’re writing, even if we’re writing tests with TDD. The idea here is not to use this information in the test.

Such tests are not tied to the details of the implementation, so when the details change, the tests will not need to be changed. When the final result does not change (correct), but the test fails, this is called a false positive (fragile tests that are tied to implementation details).

2. State testing

It also happens that the called object mutates the state out-of-process dependencies, for example, databases. In this case, the object under test will not return enough data for us to evaluate its performance, since its observable behavior is hidden from the client.

This leads to the fact that we start using the implementation details (the tests become more fragile) of the DB in the test. In this case, this is knowledge about the database dialect, table names, column types, etc. These data may change over time.

What to do to improve the situation? In many cases, other methods of the object under test may be preferred (as an option), and then the implementation details in the test will again be unknown.

3. Behavior check

The most sensitive tests are those that test:

  • How many times was the method called?

  • What parameters were transferred to this or that place?

  • In what sequence were the calls made?

  • etc.

Despite the fact that such tests are the most fragile, because almost any change of details will break the test, even if the final result is correct (false activations), they also sometimes save us:

  • Test the class Clientthat we sent the correct data to the “network”

  • “Carved in stone” is a complex algorithm/business process that should not change

  • Commit a contract with an out-of-process dependency

  • In most cases, such tests should be avoided.

In the second part, we will analyze unit tests in more detail, and compare the two schools of unit testing for the millionth time.

Related posts