1. Introduction to TDD
Test-Driven Development is placed in contrast with a traditional code-first approach to show how it changes the development process. The Red-Green-Refactor cycle is explained alongside the main reasons for using TDD and the misconceptions that often distort its purpose.
- What is Test-Driven Development and why is it worth using?
- Differences between the traditional approach and TDD,
- The Red – Green – Refactor cycle,
- The most common misconceptions about TDD.
2. Basics of testing in Python
Python testing starts with the mechanics of building and running simple automated checks. The section compares unittest with pytest, explains the structure of a basic unit test, and works through common assertions such as assertEqual, assertTrue, and assertRaises.
- introduction to unittest – the standard testing framework in Python,
- alternative: pytest – faster and simpler testing,
- structure of a simple unit test,
- example assertions (assertEqual, assertTrue, assertRaises, etc.).
3. First steps with TDD
Writing a failing test before implementation sets the pace for the core TDD workflow. Participants practice adding only the minimal code needed to pass, then refactoring after success and repeating the cycle as functionality expands into larger, coherent increments.
- writing the first test before writing the code,
- creating minimal code that satisfies the test,
- refactoring after the test passes,
- repeating the cycle for the development of greater functionality.
4. TDD on functions and classes
From small functions to object behavior, test design is adapted to the structure of Python code. The training shows a bottom-up approach to function testing, methods for validating classes and methods, and the use of setUp and tearDown to prepare and clean test environments.
- testing functions: bottom-up approach,
- testing classes and methods – testing object behaviors,
- creating setups (setUp) and teardowns (tearDown) in tests.
5. Advanced testing techniques
When code interacts with APIs, databases, or files, isolation techniques become essential for reliable automated tests. This part introduces mocking and stubbing with unittest.mock, test parameterization in pytest, and ways to structure larger suites so they remain manageable over time.
- mocking and stubbing in tests (unittest.mock),
- testing code dependent on API, databases, files,
- parameterization of tests using pytest.mark.parametrize,
- organization of larger test suites in the project.
6. Best practices in TDD
Good TDD depends not only on writing tests early, but on choosing the right level of verification for each change. Attention is given to balancing unit and integration tests, keeping tests readable as documentation, and preventing overengineered or misleading test designs.
- when to write unit tests, and when integration tests?
- tests and code documentation,
- how to avoid overengineering in tests?
- typical pitfalls in TDD and how to avoid them.
6. Best practices in TDD
Deciding between unit and integration tests is addressed in the context of maintainable Python code and realistic project scope. The section also covers tests as living documentation, common TDD mistakes, and ways to avoid unnecessary complexity in the test layer.
- when to write unit tests, and when integration tests?
- tests and code documentation,
- how to avoid overengineering in tests?
- typical pitfalls in TDD and how to avoid them.
7. Practical project
A simple application such as a task manager or mini API becomes the vehicle for applying TDD across a full development flow. Participants move feature by feature, writing tests first, evolving code incrementally, and using the test suite to refactor safely as the project grows.
- development of a simple application (e.g. task management system, mini API),
- application of TDD at every stage of the project,
- refactoring with the use of tests.