Material

About Python tests

Roadmap stageTesting →

How do you test code before sending it to production?

Below is an answer option that shows a systematic approach to quality. The specific set of checks depends on the product, the risks, and the team's process.

  1. I run quick checks locally: linters, static analysis and unit tests.
  2. After submitting changes, CI repeats the checks in a clean environment and runs broader test suites.
  3. Integration, end-to-end and regression scenarios are launched on the test bench. These concepts overlap, but are not synonymous: end-to-end describes the coverage of the entire system, and regression testing verifies that the already working functionality is not broken.
  4. If the team's process allows it, QA performs exploratory and manual testing.
  5. After deployment, smoke tests are launched and metrics, logs and alerts are checked.

Unit tests

A unit test tests a small unit of behavior in isolation and must be executed quickly and deterministically.

  • Models and functions: We check significant branches, boundary values, errors and business invariants.
  • Service layer: We pass external dependencies explicitly and, if necessary, replace them with test implementations or mock objects.
  • Validation: We separately check our own validators and important contracts. There is usually no need to retest Pydantic's default behavior.
  • Side effects: We check events, logs and the creation of related entities only when they are part of the observable contract.

A test that accesses a real database, queue, or file system is usually already classified as an integration test, even if it is run next to unit tests.

Integration tests

They test the interaction of several real components: for example, a repository with PostgreSQL, a handler with a message broker, or a FastAPI application with a test database. Controllable fixtures, data isolation, and a repeatable environment are especially important here.

HTTP API tests

At the API boundary it is useful to check:

  • status codes and response format;
  • input validation and error model;
  • authentication and authorization;
  • data retention and other significant effects;
  • behavior when dependencies are unavailable.

If internal dependencies are completely replaced by mock objects, such a test primarily checks the contract of the HTTP layer. If the application works with a real test database and several layers, this is an integration test.

End-to-end and regression tests

An end-to-end test runs a user or business scenario through the entire system. For example: create a user, collect a cart, place and pay for an order. These tests provide high confidence, but are typically slower and more expensive to maintain, so they cover key scenarios rather than every combination of inputs.

Official sources

  • pytest: documentation
  • pytest: fixtures
  • pytest: monkeypatch
  • FastAPI: testing
  • FastAPI: asynchronous tests
  • unittest.mock in the Python documentation