Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Pytest Essentials: Test Discovery, Fixtures, and Parametrization

Tech May 12 29

pytest is a feature‑rich Python testing framework that simplifies writing and running tests. It provides automatic test discovery, powerful fixture management, and built‑in support for parameterized testing.

Installation

Install pytest using pip:

pip install -U pytest
pytest --version

Often used plugins can be captured in a requirements.txt file:

pytest
pytest-xdist
pytest-ordering
pytest-rerunfailures
allure-pytest
pyyaml
requests

Then install them all at once:

pip install -r requirements.txt

Test Discovery and Customisation

By default, pytest locates test modules named test_*.py or *_test.py, classes prefixed with Test (without an __init__ method), and functions or methods starting with test_.

You can override these conventions through a pytest.ini file placed at the project root:

[pytest]
testpaths = ./tests
python_files = a*
python_classes = b*
python_functions = c*

Running Tests

Command Line

Navigate to your project directory and execute:

pytest

Via pytest.main()

Create a runner script, e.g. run_tests.py:

import pytest

if __name__ == "__main__":
    pytest.main(["-vs"])
    # Target a specific test
    # pytest.main(["-vs", "test_module.py::TestSuite::test_case"])

Using pytest.ini

The configuration file is always loaded. Common settings:

[pytest]
addopts = -vs -m "smoke"
testpaths = ./tests
markers =
    smoke: smoke tests
    regression: full regression suite

Setup and Teardown Hooks

pytest provides several levels of setup/teardown hooks. The following examples use print statements to illustrate execution order.

Module level – runs once per module.

def setup_module():
    print("before all tests in module")

def teardown_module():
    print("after all tests in module")

Function level – applies to standalone test functions (not inside a class).

def setup_function():
    print("before each function")

def teardown_function():
    print("after each function")

Class level – once before and after all tests in a class.

class SampleTests:
    @classmethod
    def setup_class(cls):
        print("setup once for the class")

    @classmethod
    def teardown_class(cls):
        print("teardown once for the class")

Method level – around each test method.

class SampleTests:
    def setup_method(self, method):
        print(f"before method {method.__name__}")

    def teardown_method(self, method):
        print(f"after method {method.__name__}")

Instance‑level setup/teardown (similar to setup_method/teardown_method but defined as plain methods).

class SampleTests:
    def setup(self):
        print("preparing test instance")

    def teardown(self):
        print("cleaning up test instance")

Fixtures

Fixtures offer reusable setup logic. Their scope is controllled by the scope parameter: function (default), class, module, or session.

import pytest

@pytest.fixture
def sample_dataset():
    return ["alpha", "beta", "gamma"]

@pytest.fixture
def processed_data(sample_dataset):
    return [item.upper() for item in sample_dataset]

def test_conversion(processed_data):
    assert processed_data == ["ALPHA", "BETA", "GAMMA"]

Optional parameters like autouse=True activate a fixture automatically for every test.

Skipping Tests

Unconditionally skip:

@pytest.mark.skip(reason="not implemented yet")
def test_draft_feature():
    pass

Conditionally skip:

import sys

@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires Python 3.10+")
def test_new_syntax():
    pass

Assertions

pytest uses the standard assert statement and provides clear failure messages.

def test_math():
    assert 2 + 2 == 4
    assert "pytest" in "pytest framework"
    assert isinstance(42, int)

def test_exception():
    import pytest
    with pytest.raises(ZeroDivisionError):
        1 / 0

Parametrization

Use @pytest.mark.parametrize to run a test function with multiple input sets.

import pytest

def add(a, b):
    return a + b

@pytest.mark.parametrize(
    "x, y, expected",
    [
        (1, 2, 3),
        (-1, 5, 4),
        (0, 0, 0),
    ],
)
def test_add(x, y, expected):
    assert add(x, y) == expected

Test Reports

Generate a JUnit‑style XML report:

pytest --junitxml=report.xml

For an HTML report (requires pytest-html):

pytest --html=report.html

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Comprehensive Guide to Hive SQL Syntax and Operations

This article provides a detailed walkthrough of Hive SQL, categorizing its features and syntax for practical use. Hive SQL is segmented into the following categories: DDL Statements: Operations on...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.