Skip to main content

Pytest (Parametrize) Suite

image image image image Test & Lint Coverage Code style: black

A tiny plugin for writing clean, easy-to-read, parametrized tests in pytest.

Why?

Pytest's parametrize is a powerful way to write input-output testing to rapidly expand your test coverage while minimizing the number of test assertions you must write. Unfortunately, as the complexity of your test suite grows, it can become difficult to keep track of individual test cases.

One way to get cleaner test output is by assigning descriptive ids and argnames to each parametrized case. However, the current methodologies available result in either very verbose setup, or difficult-to-track ids and names.

Enter pytest-parametrize-suite. With this marker, you define your test ids and names in-line with the values you intend to pass into your test, keeping your identifiers tightly coupled to your test cases and encouraging a delightful testing experience as a result.

Quickstart

Install With PIP

pip install -U pytest-parametrize-suite

Install With Poetry

poetry add --group=test pytest-parametrize-suite

Using the plugin

The plugin provides a single entrypoint in a pytest marker called suite.

The suite marker takes any number of keyword arguments. Each entry in should be a Mapping of argname->argvalue and all entries should be the same exact shape.

This gives developers the ability to

Example

Given the following module:

# iso8601.py

from __future__ import annotations

import datetime


def iso8601(
    date_obj: datetime.date | datetime.datetime | datetime.time | datetime.timedelta
) -> str:
    """Format a Python date/time object into an ISO8601 string."""

    if isinstance(date_obj, (datetime.date, datetime.time)):
        return date_obj.isoformat()
    if isinstance(date_obj, datetime.timedelta):
        return timedelta_isoformat(date_obj)
    raise ValueError(
        f"Unrecognized value of type: {date_obj.__class__.__name__}: {date_obj}"
    )


def timedelta_isoformat(delta: datetime.timedelta) -> str:
    """Why isn't this part of the stdlib?"""
    usecs = abs(
        (delta.days * 24 * 60 * 60 + delta.seconds) * 1000000 + delta.microseconds
    )
    seconds, usecs = divmod(usecs, 1000000)
    minutes, seconds = divmod(seconds, 60)
    hours, minutes = divmod(minutes, 60)
    days, hours = divmod(hours, 24)
    fmt = f"P{days}DT{hours}H{minutes}M{seconds}.{usecs:06}S"
    return fmt

Writing With pytest-parametrize-suite:

# test_iso8601.py

from __future__ import annotations

import datetime

import pytest

from example.iso8601 import iso8601


@pytest.mark.suite(
    datetime=dict(
        given_date_obj=datetime.datetime(1970, 1, 1),
        expected_date_str="1970-01-01T00:00:00",
    ),
    date=dict(
        given_date_obj=datetime.date(1970, 1, 1),
        expected_date_str="1970-01-01",
    ),
    time=dict(
        given_date_obj=datetime.time(),
        expected_date_str="00:00:00",
    ),
    timedelta=dict(
        given_date_obj=datetime.timedelta(1, 1, 1),
        expected_date_str="P1DT1.000001S",
    )
)
def test_iso8601(given_date_obj, expected_date_str):
    # When
    date_str = iso8601(given_date_obj)
    # Then
    assert date_str == expected_date_str

Writing Without pytest-parametrize-suite:

# test_iso8601.py

from __future__ import annotations

import datetime

import pytest

from example.iso8601 import iso8601


@pytest.mark.parametrize(
    argnames=("given_date_obj", "expected_date_str"),
    argvalues=[
        (datetime.datetime(1970, 1, 1), "1970-01-01T00:00:00"),
        (datetime.date(1970, 1, 1), "1970-01-01"),
        (datetime.time(), "00:00:00"),
        (datetime.timedelta(1, 1, 1), "P1DT1.000001S")
    ],
    ids=["datetime", "date", "time", "timedelta"]
)
def test_iso8601(given_date_obj, expected_date_str):
    # When
    date_str = iso8601(given_date_obj)
    # Then
    assert date_str == expected_date_str

Running the test defined in the example outputs the following:

❯ pytest test_iso8601.py -v
=============================== test session starts ===============================
platform darwin -- Python 3.11.0, pytest-7.2.1, pluggy-1.0.0 -- /Users/god/Library/Caches/pypoetry/virtualenvs/pytest-parametrize-suite-TGMGi3Zp-py3.11/bin/python
cachedir: .pytest_cache
rootdir: /Users/god/PycharmProjects/pytest-parametrize-suite
plugins: parametrize-suite-23.1.0, cov-4.0.0
collected 4 items                                                                 

src/pytest_parametrize_suite/example.py::test_iso8601[datetime] PASSED      [ 25%]
src/pytest_parametrize_suite/example.py::test_iso8601[date] PASSED          [ 50%]
src/pytest_parametrize_suite/example.py::test_iso8601[time] PASSED          [ 75%]
src/pytest_parametrize_suite/example.py::test_iso8601[timedelta] PASSED     [100%]

================================ 4 passed in 0.02s ================================

As you can see, we get a developer-friendly output for our parametrized tests while minimizing the amount of cognitive overhead it takes to understand and develop our test cases.

Happy testing! ✅

Metadata

Release files for pytest-parametrize-suite 23.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytest-parametrize-suite 23.1.2
File Size Uploaded
pytest_parametrize_suite-23.1.2.tar.gz 18.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pytest-parametrize-suite 23.1.2
File Interpreter ABI Platform
pytest_parametrize_suite-23.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 36.2 kB

Release files / pytest_parametrize_suite-23.1.2.tar.gz

Download URL pytest_parametrize_suite-23.1.2.tar.gz
Size 18.1 kB
Tags Source
SHA-256 checksum
How to use checksums
f3e11143d38694e6ddc55876070018351c570df25ce45041eec590191a907d1f
BLAKE2b-256 checksum
How to use checksums
98aca774673d4a26cd113c4b8e1b9c92a6ef11266db8bd6444be1c9d69c08794
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.11.0 Darwin/21.6.0

Release files / pytest_parametrize_suite-23.1.2-py3-none-any.whl

Download URL pytest_parametrize_suite-23.1.2-py3-none-any.whl
Size 18.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a3a6258cef97943c8e7321099e903a4f782dac1bb8416d7bef37b9ee334dca2f
BLAKE2b-256 checksum
How to use checksums
055739f602d4af4f391976e355dc615cdbb0c2a18df1a44af8785d0b69ad49da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.11.0 Darwin/21.6.0

Release history Release notifications | RSS feed

This release

23.1.2 This release

2 release files

23.1.1

2 release files

23.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page