Test Driven Development

Purpose: Define requirements.

Focus: Write a minimal amount of test code to make a test fail.

Additional Instructions: Run a test to make sure it fails – that is valuable information. Aim at many small tests with no more than few assertions. Avoid testing central functionality as long as possible. Write specific tests to force the desired production code.
Purpose: Fulfill test requirements.

Focus: Write a minimal amount of production code to make a test pass.

Additional Instructions: Make sure all tests pass. Write the simplest code that will make a test pass, even if it means returning the constant. Make code general to cover the growing number of tests. First, make it work, then make it clean (Refactor step).
Purpose: Clean up code.

Focus: Make code and architecture clean in production and tests.

Additional Instructions: Make sure all tests pass. Look for code smells and use refactoring recipes. Parametrize tests to avoid duplication. Separate set up and clean up code from tests. Organize code into clean architecture. Don't add functionality, only structure.

Test-Driven Development

3 rules:

  1. You’re not allowed to write any production code until You first write a failing test
  2. You’re not allowed to write more of the test than is sufficient to fail
  3. You’re not allowed to write more production code than is sufficient to pass the currently failing test
  4. Tests are getting more specific while production code is getting more general

Make a test that forces You to create code that You want to write. When tests pass then refactor.

Don’t do too much too fast. Engage a minimum amount of brain cells.

Don’t go for the gold. Avoid central behavior, leave it for last. First test everything else around it.

Have not more than a few asserts per unit test, and more asserts are fine for higher-level tests (especially E2E).

Don’t create tests in a structure that code has.

Test-Driven Development is hard and it takes months of practice to be proficient in it. Learn it first and then You can bring it to work.

TDD is double-entry bookkeeping for programming. There are two strategies: Outside-in (London School of TDD, Behaviour Verification, Mockist) and Inside-out (Classic TDD, State-Based Verification).

Except for Unit tests we have Component level tests / Acceptance tests (behave) and Integration level tests. You can use TDD for all of them. You can start with the highest level tests first and work your way down or start from unit tests and work your way up.

Why use TDD: The Outrageous Cost of Skipping TDD & Code Reviews


Sources:
Test-Driven Development By Example (Kent Beck)
The Clean Coder: A Code of Conduct for Professional Programmers (Robert C. Martin)
Test-Driven Development with Python: Obey the Testing Goat: Using Django, Selenium, and JavaScript (Harry Percival)