Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Pytest Essentials: Test Discovery, Fixtures, and Parametrization

Tech May 12 2

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...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

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