pytest

**pytest** is the **most popular Python testing framework**, offering simple syntax, powerful fixtures, and extensive plugin ecosystem that makes writing and running tests enjoyable and productive. **What Is pytest?** - **Definition**: Python test framework for writing and executing tests. - **Philosophy**: Simple yet powerful, convention over configuration. - **Key Strength**: Minimal boilerplate, intuitive syntax. - **Ecosystem**: 800+ plugins for extending functionality. - **Adoption**: De facto standard for Python testing. **Why pytest Matters** - **Simplicity**: Write tests as plain functions with assert statements - **Fixtures**: Powerful reusable setup/teardown mechanisms - **Parametrization**: Test multiple inputs with single test function - **Plugins**: Extensive ecosystem covers almost any use case - **Integration**: Works with Django, Flask, asyncio, etc. - **Productivity**: Less boilerplate = write tests faster - **Debugging**: Detailed failure information with pytest output **Key Features** **1. Simple Assertions** ```python def test_user(): user = User("Alice", age=30) assert user.name == "Alice" # Clear, readable assert user.age == 30 assert user.is_adult() # Works with methods ``` **2. Fixtures (Setup & Teardown)** ```python import pytest @pytest.fixture def database(): """Setup: connect to database.""" db = Database() db.connect() yield db # Test runs here db.disconnect() # Teardown def test_query(database): """Fixture automatically injected as parameter.""" result = database.query("SELECT * FROM users") assert len(result) > 0 ``` **3. Parametrization** ```python @pytest.mark.parametrize("input,expected", [ (1, 2), (2, 4), (3, 6) ]) def test_double(input, expected): """Test runs once for each parameter pair.""" assert input * 2 == expected ``` **4. Markers & Test Selection** ```python @pytest.mark.slow def test_slow_operation(): # Long-running test pass @pytest.mark.skip(reason="Not implemented") def test_future(): pass # Command line: pytest -m "not slow" ``` **5. Exception Testing** ```python def test_division_by_zero(): """Test that exceptions are raised correctly.""" with pytest.raises(ZeroDivisionError): 1 / 0 ``` **Common Test Patterns** **Mocking External Dependencies**: ```python def test_api_call(mocker): """Mock external API calls.""" mock_api = mocker.patch("requests.get") mock_api.return_value.json.return_value = {"status": "ok"} result = fetch_data() assert result["status"] == "ok" ``` **Temporary Files**: ```python def test_file_processing(tmp_path): """pytest provides temporary directories.""" file = tmp_path / "test.txt" file.write_text("hello") result = process_file(file) assert result == "HELLO" ``` **Fixtures with Scope**: ```python @pytest.fixture(scope="session") def expensive_resource(): """Created once per test session.""" return ExpensiveSetup() @pytest.fixture(scope="function") def fresh_db(): """Created for each test function.""" return Database() ``` **Configuration (pytest.ini)** ```ini [pytest] testpaths = tests python_files = test_*.py python_functions = test_* addopts = -v --tb=short markers = slow: marks tests as slow integration: integration tests ``` **Running Tests** ```bash # All tests pytest # Specific file pytest tests/test_user.py # Specific test pytest tests/test_user.py::test_login # With coverage pytest --cov=myapp # Parallel execution pytest -n 4 # Stop on first failure pytest -x # Verbose output pytest -v # Run marked tests pytest -m slow ``` **Popular Plugins** | Plugin | Purpose | |--------|---------| | pytest-cov | Code coverage reports | | pytest-xdist | Parallel test execution | | pytest-mock | Enhanced mocking helpers | | pytest-django | Django testing utilities | | pytest-asyncio | Async test support | | pytest-timeout | Test timeout limits | | pytest-repeat | Repeat tests N times | **Best Practices** 1. **One assertion per test** (usually): Easier to understand failures 2. **Descriptive names**: `test_login_with_invalid_password` better than `test_login` 3. **Arrange-Act-Assert**: Setup → Action → Verification 4. **Use fixtures**: Don't repeat setup code 5. **Independent tests**: No test should depend on another 6. **Mock external deps**: Don't call real APIs/database 7. **Test behavior, not implementation**: Test what it does, not how 8. **Parametrize similar tests**: Reduce code duplication **pytest vs unittest** | Feature | pytest | unittest | |---------|--------|----------| | Syntax | assert statements | self.assertEqual() | | Fixtures | Powerful, flexible | setUp/tearDown | | Parametrization | Built-in | Manual loops | | Plugins | 800+ available | Limited | | Learning Curve | Gentle | Steeper | | Enterprise Use | Increasingly standard | Legacy codebases | **Common Assertions** ```python assert x == 5 # Equality assert x > 0 # Comparison assert "hello" in text # Membership assert user is None # Identity assert callable(func) # Type checking ``` **Test Structure Template** ```python import pytest from mymodule import Calculator @pytest.fixture def calc(): return Calculator() def test_addition(calc): """Test that addition works correctly.""" # Arrange a, b = 2, 3 # Act result = calc.add(a, b) # Assert assert result == 5 ``` pytest is the **gold standard for Python testing** — combining simplicity for beginners with power for advanced users, making it the framework of choice for professionals and open-source projects worldwide.

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account