C++

Modern C++ guidance and idioms.

6 posts, grouped by resource

Best Practice 6

TEST-001 Arrange, Act, Assert GoPythonRustTesting

When writing unit-tests, always follow the three-A’s: Arrange, Act, Assert. This divides every test into three distinct phases:

  • Arrange: set up the test-case, including any inputs, mocks, and expected outputs.

  • Act: perform the one action under test.

  • Assert: check the outcome of the action, including any return values and expected side effects.

Tip

Keep exactly one action in the Act phase. If you need two, that’s usually two tests.
TEST-002 Keep tests small and focused GoPythonRustTestingDesign

Each unit test should verify one specific behavior. Avoid exercising multiple behaviors or features within a single test case.

Tip

A useful heuristic: if you cannot describe what a test checks without using “and”, it is testing more than one behavior and should be split.
TEST-003 Avoid creating side-effects in tests GoPythonRustTesting

A unit test must not depend on or alter state that lives outside its own scope. Do not read or mutate global variables, singletons, static fields, the filesystem, environment variables, or any other resource that another test can also reach.

Tip

If a test only passes when the suite runs in a particular order, it is sharing state with another test.
TEST-004 Test behavior, not implementation GoPythonRustTesting

Write tests against the observable behavior of code, not the way that behavior is implemented. Avoid expectations that restate the implementation – most commonly an expected value copied verbatim from the function body. Such a test passes by construction and verifies nothing about correctness.

Tip

If the only way to derive the expected value is to read the implementation, you are testing the implementation. Assert a documented property instead.
TEST-005 Prefer black-box testing GoPythonRustTestingDesign

Prefer testing the public interface of a unit over its private implementation details. A test should exercise what a unit promises to its callers, not how it achieves it internally. This style is called black-box testing: the tester knows the external behavior but treats the internal structure as opaque.

Tip

If you find yourself needing to reach into private helpers to test them, that is usually a design smell. Consider extracting those helpers into their own unit with its own public interface, and test them there.
TEST-006 Do not write test-aware code GoPythonRustTestingDesign

Do not write code that detects whether it is running under test and changes its behavior – test-aware code. A unit that branches on a test flag, the presence of a test runner, the presence of an environment variable, or a test-only build runs a different path under test than it does in production, so the test verifies behavior you do not ship. Instead, make code testable through design – typically dependency injection – so that tests substitute collaborators without the unit ever knowing.

Tip

If a test only passes because the code skipped its real work, the test is exercising the test-mode path, not the production behavior. It has little value as a test.