Pytest Cheat Sheet

Pytest Cheat Sheet

Pytest is a powerful and easy-to-use testing framework for Python. This cheat sheet covers its essential features, commands, and best practices to streamline your testing workflow.


Getting Started

Installation

Install pytest using pip:

pip install pytest

Basic Test File

Save the following as test_sample.py:

def test_example():
    assert 1 + 1 == 2

Run tests:

pytest

Writing Tests

Test Naming Convention

  • Test files should start with test_ or end with _test.
  • Test functions should start with test_.

Assertions

Use Python’s assert statement for validations:

def test_math():
    assert 2 * 2 == 4
    assert "abc" in "abcdef"

Markers

Markers allow you to categorize tests:

import pytest

@pytest.mark.slow
def test_slow_operation():
    import time
    time.sleep(5)
    assert True

Run marked tests:

pytest -m slow

Fixtures

Basic Fixture

Fixtures set up resources needed for your tests:

import pytest

@pytest.fixture
def sample_data():
    return [1, 2, 3]

def test_data_length(sample_data):
    assert len(sample_data) == 3

Fixture Scope

Control how often a fixture is run:

  • function (default)
  • class
  • module
  • session
@pytest.fixture(scope="module")
def db_connection():
    return create_database_connection()

Running Tests

Run All Tests

pytest

Run Specific File

pytest test_file.py

Run Specific Test

pytest test_file.py::test_function

Verbose Output

pytest -v

Test Discovery

Check Collected Tests

pytest --collect-only

Ignore Files/Directories

Add a pytest.ini file:

[pytest]
addopts = --maxfail=3 --disable-warnings
norecursedirs = .git venv

Parameterized Tests

Test multiple input values using @pytest.mark.parametrize:

@pytest.mark.parametrize("input,expected", [
    (1, 2),
    (2, 4),
    (3, 6)
])
def test_double(input, expected):
    assert input * 2 == expected

Debugging

Drop Into Debugger on Failure

pytest --pdb

Use -s to show print statements:

pytest -s

Plugins

Extend pytest with plugins:

pip install pytest-cov  # For coverage reporting

Example usage:

pytest --cov=my_module

Useful Plugins

  • pytest-mock: Mocking library integration.
  • pytest-django: Django testing support.
  • pytest-xdist: Run tests in parallel.

Skipping and Expected Failures

Skip a Test

@pytest.mark.skip(reason="Not implemented")
def test_placeholder():
    assert False

Conditionally Skip

@pytest.mark.skipif(sys.version_info < (3, 8), reason="Requires Python 3.8")
def test_new_feature():
    assert True

Expected Failures

@pytest.mark.xfail(reason="Known bug")
def test_known_issue():
    assert False

Test Coverage

Install Coverage Plugin

pip install pytest-cov

Run Tests with Coverage

pytest --cov=my_module

Generate HTML Report

pytest --cov=my_module --cov-report=html

Using pytest-mock

Mocking with pytest-mock

Use pytest-mock to simplify mocking in your tests:

pip install pytest-mock

Example:

def test_mock_function(mocker):
    mock_function = mocker.patch("module_name.function_name")
    mock_function.return_value = "mocked_value"

    result = module_name.function_name()
    assert result == "mocked_value"

Checking Exception Handling

You can use pytest.raises to ensure exceptions are properly handled:

def test_exception_handling():
    with pytest.raises(ValueError, match="Invalid input"):
        function_that_raises_value_error()

Using conftest.py

The conftest.py file is a special file used to share fixtures and hooks across multiple test files in a pytest project. Place it in the root directory or any subdirectory of your tests.

Example: Shared Fixture

Create conftest.py:

import pytest

@pytest.fixture
def shared_fixture():
    return "shared resource"

Use the fixture in your test files without importing:

def test_shared_fixture(shared_fixture):
    assert shared_fixture == "shared resource"

Advanced Usage

  • Hooks: Customize pytest behavior, such as modifying command-line options or test discovery.
  • Scoped Fixtures: Centralize setup and teardown logic.

Example of a hook in conftest.py:

def pytest_addoption(parser):
    parser.addoption("--custom-flag", action="store", default="default_value")

@pytest.fixture
def custom_flag(request):
    return request.config.getoption("--custom-flag")

Run with:

pytest --custom-flag=some_value

Best Practices

  1. Use Fixtures: Reuse setup/teardown code.
  2. Categorize Tests: Use markers for organization.
  3. Keep Tests Isolated: Ensure tests do not depend on each other.
  4. Fail Fast: Use --maxfail=1 during debugging.
  5. Write Descriptive Names: Use meaningful test and function names.

With this cheat sheet, you can start using pytest effectively for your testing needs, including advanced use cases like mocking, shared fixtures, and exception handling. Happy testing!