Back to blog

Python Testing với pytest: Viết Bộ Test Toàn Diện

pythonpytesttestingtddquality-assurance
Python Testing với pytest: Viết Bộ Test Toàn Diện

Python Testing với pytest: Viết Bộ Test Toàn Diện

Testing là thiết yếu để xây dựng phần mềm đáng tin cậy. pytest là testing framework phổ biến nhất của Python—đơn giản để bắt đầu, nhưng đủ mạnh cho các ứng dụng phức tạp. Hướng dẫn này covers mọi thứ từ basic tests đến advanced patterns như fixtures, parametrization, và mocking.

Những Gì Bạn Sẽ Học

✅ pytest fundamentals và installation
✅ Viết và tổ chức test cases
✅ Fixtures cho test setup/teardown
✅ Parametrized tests cho data-driven testing
✅ Mocking và patching với pytest-mock
✅ Test coverage với pytest-cov
✅ Testing async code
✅ Best practices cho maintainable tests

Điều Kiện Tiên Quyết

Trước khi tìm hiểu pytest, bạn nên hiểu:


Ghi chú: Phần này chứa các ví dụ code tương tự phiên bản tiếng Anh. Để tiết kiệm không gian, chúng tôi tập trung vào giải thích khái niệm bằng tiếng Việt và giữ nguyên code examples.

1. Getting Started với pytest

Installation: pip install pytest và các plugins hữu ích: pytest-cov (coverage), pytest-mock (mocking), pytest-asyncio (async testing).

Test Discovery: pytest tự động tìm tests:

  • Files named test_*.py hoặc *_test.py
  • Functions bắt đầu với test_
  • Classes bắt đầu với Test

Running tests: pytest (all tests), pytest -v (verbose), pytest test_file.py::test_function (specific test).

2. Assertions và Test Outcomes

Basic assertions: Dùng Python's built-in assert statement. pytest provides detailed failure messages automatically.

Testing exceptions: Dùng with pytest.raises(ExceptionType) để test exceptions. Có thể check message với match parameter.

Approximate comparisons: Dùng pytest.approx() cho floating point comparisons với relative hoặc absolute tolerance.

3. Test Organization

Project structure: Separate src/ và tests/ directories. conftest.py cho shared fixtures.

Configuration: pytest.ini hoặc pyproject.toml với [tool.pytest.ini_options].

Markers: @pytest.mark.slow, @pytest.mark.skip, @pytest.mark.xfail để categorize và control tests. Run với pytest -m slow.

4. Fixtures: Setup và Teardown

Basic fixtures: Functions decorated với @pytest.fixture provide test data. Tests request fixtures as parameters.

Fixture scopes: function (default, new mỗi test), class, module, session. Higher scope = less setup overhead.

Teardown với yield: Code sau yield runs sau test completion. Perfect cho cleanup resources.

Factory fixtures: Return function thay vì value cho flexible test data creation.

Built-in fixtures: tmp_path (temp directory), capsys (capture stdout/stderr), monkeypatch (modify objects/env vars).

5. Parametrized Tests

Basic parametrization: @pytest.mark.parametrize("param1,param2", [(val1, val2), ...]) runs test với multiple inputs.

IDs cho clarity: pytest.param(value, id="descriptive_name") makes output readable.

Multiple decorators: Stacking @pytest.mark.parametrize creates all combinations.

Parametrized fixtures: @pytest.fixture(params=[...]) runs dependent tests with each param.

6. Mocking và Patching

pytest-mock: mocker fixture provides mocker.patch(), mocker.Mock(), mocker.spy().

Patching functions: mocker.patch("module.function", return_value=...) replaces function.

Patching methods: mocker.patch.object(obj, "method", return_value=...) replaces method.

Environment variables: monkeypatch.setenv("VAR", "value"), monkeypatch.delenv("VAR").

Spy: mocker.spy(obj, "method") tracks calls without replacing implementation.

7. Testing Async Code

Setup: Install pytest-asyncio, configure asyncio_mode = "auto" trong pyproject.toml.

Async tests: @pytest.mark.asyncio decorator, async def test_...(), await coroutines.

Async fixtures: @pytest.fixture với async def, dùng yield cho cleanup.

8. Test Coverage

Setup: pip install pytest-cov.

Running: pytest --cov=myapp --cov-report=term-missing shows uncovered lines.

HTML report: pytest --cov=myapp --cov-report=html generates browsable report.

Threshold: pytest --cov-fail-under=80 fails nếu coverage < 80%.

Configuration: [tool.coverage.run] và [tool.coverage.report] trong pyproject.toml.

9. Real-World Example

Example trong EN version shows complete UserService với:

  • Mock database fixture
  • Test class organization
  • Parametrized invalid email tests
  • Authentication test scenarios
  • Fixture chaining

Pattern: separate fixture creation, group related tests in classes, use descriptive names.

10. Best Practices

✅ Do's:

  • Descriptive test names: test_login_with_invalid_password_raises_auth_error
  • One assertion per test (when practical)
  • Use fixtures cho setup
  • Use parametrize cho multiple similar tests
  • Keep tests isolated - no shared state

❌ Don'ts:

  • Don't test implementation details (private methods)
  • Don't use magic numbers without context
  • Don't have tests depend on each other
  • Don't ignore test failures

11. Common Pitfalls

Pitfall 1: Flaky tests - Timing-dependent tests. Use proper waits hoặc mocking instead of time.sleep().

Pitfall 2: Over-mocking - Testing mocks thay vì real code. Only mock external dependencies.

Pitfall 3: Not cleaning up - Files/resources left behind. Use tmp_path fixture hoặc teardown.

Summary

Trong guide này, bạn đã học:

✅ pytest fundamentals: installation, test discovery, assertions
✅ Test organization với classes, markers, và configuration
✅ Fixtures cho setup/teardown với different scopes
✅ Parametrized tests cho data-driven testing
✅ Mocking và patching với pytest-mock
✅ Testing async code với pytest-asyncio
✅ Test coverage với pytest-cov
✅ Best practices cho maintainable tests

Testing là skill improves với practice. Start với simple unit tests, gradually add sophisticated patterns khi codebase grows.

Bước Tiếp Theo

Giờ bạn đã hiểu testing, khám phá các chủ đề liên quan:

Thêm Python Deep Dives:

Áp Dụng Testing trong Web Development:

Quay Lại Roadmap:


Thuộc chuỗi bài Lộ Trình Học Python

📬 Đăng ký nhận bản tin

Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.

Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.

💬 Comments

Đăng nhập để bình luận

Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.