Back to Curriculum

Testing with unittest and pytest

📚 Lesson 15 of 20 ⏱️ 50 min

Testing with unittest and pytest

50 min

Testing is crucial for ensuring code quality and preventing bugs. Well-written tests serve as documentation, catch regressions, and give confidence when refactoring. Tests should cover normal cases, edge cases, and error conditions. A good test suite is fast, isolated, repeatable, and self-validating.

Python's built-in `unittest` framework provides a way to write and run tests. It's based on JUnit and follows the xUnit testing pattern. Tests are organized into test cases (classes inheriting from `unittest.TestCase`) with test methods starting with `test_`. The framework provides assertion methods like `assertEqual`, `assertTrue`, and `assertRaises`.

`pytest` is a popular third-party testing framework that offers more features and a simpler syntax. It automatically discovers and runs tests, provides better error messages, supports fixtures for test setup/teardown, and has a rich plugin ecosystem. Many Python projects prefer pytest for its simplicity and powerful features.

Test fixtures provide setup and teardown code that runs before and after tests. In unittest, you use `setUp()` and `tearDown()` methods. In pytest, you use `@pytest.fixture` decorators, which are more flexible and can be shared across tests. Fixtures help keep tests isolated and reduce code duplication.

Test coverage measures how much of your code is tested. Tools like `coverage.py` can generate coverage reports showing which lines are executed during tests. Aim for high coverage, but remember that 100% coverage doesn't guarantee bug-free code—focus on testing important logic and edge cases.

Best practices include writing tests before or alongside code (TDD), keeping tests simple and focused, using descriptive test names, and testing behavior rather than implementation. Good tests are independent, fast, and don't rely on external resources when possible.

Key Concepts

  • Testing ensures code quality and catches bugs before production.
  • unittest is Python's built-in testing framework based on xUnit pattern.
  • pytest is a popular third-party framework with simpler syntax and more features.
  • Test fixtures provide setup and teardown code for tests.
  • Test coverage measures how much code is executed during tests.

Learning Objectives

Master

  • Writing tests with unittest.TestCase and assertion methods
  • Using pytest for simpler, more powerful testing
  • Creating and using test fixtures for setup/teardown
  • Measuring and improving test coverage

Develop

  • Test-driven development thinking
  • Understanding testing best practices and patterns
  • Writing maintainable and effective test suites

Tips

  • Write tests for normal cases, edge cases, and error conditions.
  • Use descriptive test names that explain what is being tested.
  • Keep tests simple, focused, and independent of each other.
  • Use fixtures to reduce code duplication and improve test isolation.

Common Pitfalls

  • Not writing tests, leading to bugs in production.
  • Writing tests that depend on each other or external state.
  • Testing implementation details instead of behavior.
  • Ignoring test failures or writing tests that always pass.

Summary

  • Testing is essential for code quality and preventing bugs.
  • unittest provides built-in testing capabilities.
  • pytest offers simpler syntax and more powerful features.
  • Good tests are independent, fast, and cover important scenarios.

Exercise

Write a simple test for a function using unittest.

import unittest\n\ndef add_numbers(a, b):\n  return a + b\n\nclass TestMathFunctions(unittest.TestCase):\n  def test_add_numbers(self):\n    self.assertEqual(add_numbers(2, 3), 5)\n    self.assertEqual(add_numbers(-1, 1), 0)\n    self.assertEqual(add_numbers(0, 0), 0)\n\nif __name__ == '__main__':\n  unittest.main()

Exercise Tips

  • Add tests for edge cases like negative numbers and large numbers.
  • Try rewriting the same tests using pytest for comparison.
  • Add a setUp method to demonstrate test fixtures.
  • Use assertRaises to test that functions raise appropriate exceptions.

Code Editor

Output