pytest-parametrize-suite


Namepytest-parametrize-suite JSON
Version 23.1.2 PyPI version JSON
download
home_page
SummaryA simple pytest extension for creating a named test suite.
upload_time2023-01-19 13:15:51
maintainer
docs_urlNone
authorSean Stewart
requires_python>=3.8.1,<4.0
licenseGPL-3.0
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Pytest (Parametrize) Suite

[![image](https://img.shields.io/pypi/v/pytest-parametrize-suite.svg)](https://pypi.org/project/pytest-parametrize-suite/)
[![image](https://img.shields.io/pypi/l/pytest-parametrize-suite.svg)](https://pypi.org/project/pytest-parametrize-suite/)
[![image](https://img.shields.io/pypi/pyversions/pytest-parametrize-suite.svg)](https://pypi.org/project/pytest-parametrize-suite/)
[![image](https://img.shields.io/github/languages/code-size/seandstewart/pytest-parametrize-suite.svg?style=flat)](https://github.com/seandstewart/pytest-parametrize-suite)
[![Test & Lint](https://github.com/seandstewart/pytest-parametrize-suite/workflows/Test/badge.svg)](https://github.com/seandstewart/pytest-parametrize-suite/actions)
[![Coverage](https://codecov.io/gh/seandstewart/pytest-parametrize-suite/branch/main/graph/badge.svg)](https://codecov.io/gh/seandstewart/pytest-parametrize-suite)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/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

```shell
pip install -U pytest-parametrize-suite
```

### Install With Poetry

```shell
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:**

```python
# 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:**

```python
# 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:**

```python
# 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:

```shell
❯ 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! :white_check_mark:

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "pytest-parametrize-suite",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8.1,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "Sean Stewart",
    "author_email": "sean_stewart@me.com",
    "download_url": "https://files.pythonhosted.org/packages/98/ac/a774673d4a26cd113c4b8e1b9c92a6ef11266db8bd6444be1c9d69c08794/pytest_parametrize_suite-23.1.2.tar.gz",
    "platform": null,
    "description": "# Pytest (Parametrize) Suite\n\n[![image](https://img.shields.io/pypi/v/pytest-parametrize-suite.svg)](https://pypi.org/project/pytest-parametrize-suite/)\n[![image](https://img.shields.io/pypi/l/pytest-parametrize-suite.svg)](https://pypi.org/project/pytest-parametrize-suite/)\n[![image](https://img.shields.io/pypi/pyversions/pytest-parametrize-suite.svg)](https://pypi.org/project/pytest-parametrize-suite/)\n[![image](https://img.shields.io/github/languages/code-size/seandstewart/pytest-parametrize-suite.svg?style=flat)](https://github.com/seandstewart/pytest-parametrize-suite)\n[![Test & Lint](https://github.com/seandstewart/pytest-parametrize-suite/workflows/Test/badge.svg)](https://github.com/seandstewart/pytest-parametrize-suite/actions)\n[![Coverage](https://codecov.io/gh/seandstewart/pytest-parametrize-suite/branch/main/graph/badge.svg)](https://codecov.io/gh/seandstewart/pytest-parametrize-suite)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n\nA tiny plugin for writing clean, easy-to-read, parametrized tests in pytest.\n\n## Why?\n\nPytest's `parametrize` is a powerful way to write input-output testing to rapidly \nexpand your test coverage while minimizing the number of test assertions you must \nwrite. Unfortunately, as the complexity of your test suite grows, it can become \ndifficult to keep track of individual test cases.\n\nOne way to get cleaner test output is by assigning descriptive `ids` and `argnames` to \neach parametrized case. However, the current methodologies available result in either \nvery verbose setup, or difficult-to-track ids and names.\n\nEnter `pytest-parametrize-suite`. With this marker, you define your test ids and \nnames in-line with the values you intend to pass into your test, keeping your \nidentifiers tightly coupled to your test cases and encouraging a delightful testing \nexperience as a result.\n\n## Quickstart\n\n### Install With PIP\n\n```shell\npip install -U pytest-parametrize-suite\n```\n\n### Install With Poetry\n\n```shell\npoetry add --group=test pytest-parametrize-suite\n```\n\n## Using the plugin\n\nThe plugin provides a single entrypoint in a pytest marker called `suite`. \n\nThe `suite`\nmarker takes any number of keyword arguments. Each entry in should be a Mapping of \n`argname->argvalue` and all entries should be the same exact shape.\n\nThis gives developers the ability to \n\n#### Example\n\n**Given the following module:**\n\n```python\n# iso8601.py\n\nfrom __future__ import annotations\n\nimport datetime\n\n\ndef iso8601(\n    date_obj: datetime.date | datetime.datetime | datetime.time | datetime.timedelta\n) -> str:\n    \"\"\"Format a Python date/time object into an ISO8601 string.\"\"\"\n\n    if isinstance(date_obj, (datetime.date, datetime.time)):\n        return date_obj.isoformat()\n    if isinstance(date_obj, datetime.timedelta):\n        return timedelta_isoformat(date_obj)\n    raise ValueError(\n        f\"Unrecognized value of type: {date_obj.__class__.__name__}: {date_obj}\"\n    )\n\n\ndef timedelta_isoformat(delta: datetime.timedelta) -> str:\n    \"\"\"Why isn't this part of the stdlib?\"\"\"\n    usecs = abs(\n        (delta.days * 24 * 60 * 60 + delta.seconds) * 1000000 + delta.microseconds\n    )\n    seconds, usecs = divmod(usecs, 1000000)\n    minutes, seconds = divmod(seconds, 60)\n    hours, minutes = divmod(minutes, 60)\n    days, hours = divmod(hours, 24)\n    fmt = f\"P{days}DT{hours}H{minutes}M{seconds}.{usecs:06}S\"\n    return fmt\n\n```\n\n**Writing With pytest-parametrize-suite:**\n\n```python\n# test_iso8601.py\n\nfrom __future__ import annotations\n\nimport datetime\n\nimport pytest\n\nfrom example.iso8601 import iso8601\n\n\n@pytest.mark.suite(\n    datetime=dict(\n        given_date_obj=datetime.datetime(1970, 1, 1),\n        expected_date_str=\"1970-01-01T00:00:00\",\n    ),\n    date=dict(\n        given_date_obj=datetime.date(1970, 1, 1),\n        expected_date_str=\"1970-01-01\",\n    ),\n    time=dict(\n        given_date_obj=datetime.time(),\n        expected_date_str=\"00:00:00\",\n    ),\n    timedelta=dict(\n        given_date_obj=datetime.timedelta(1, 1, 1),\n        expected_date_str=\"P1DT1.000001S\",\n    )\n)\ndef test_iso8601(given_date_obj, expected_date_str):\n    # When\n    date_str = iso8601(given_date_obj)\n    # Then\n    assert date_str == expected_date_str\n\n```\n\n**Writing Without pytest-parametrize-suite:**\n\n```python\n# test_iso8601.py\n\nfrom __future__ import annotations\n\nimport datetime\n\nimport pytest\n\nfrom example.iso8601 import iso8601\n\n\n@pytest.mark.parametrize(\n    argnames=(\"given_date_obj\", \"expected_date_str\"),\n    argvalues=[\n        (datetime.datetime(1970, 1, 1), \"1970-01-01T00:00:00\"),\n        (datetime.date(1970, 1, 1), \"1970-01-01\"),\n        (datetime.time(), \"00:00:00\"),\n        (datetime.timedelta(1, 1, 1), \"P1DT1.000001S\")\n    ],\n    ids=[\"datetime\", \"date\", \"time\", \"timedelta\"]\n)\ndef test_iso8601(given_date_obj, expected_date_str):\n    # When\n    date_str = iso8601(given_date_obj)\n    # Then\n    assert date_str == expected_date_str\n\n```\n\nRunning the test defined in the example outputs the following:\n\n```shell\n\u276f pytest test_iso8601.py -v\n=============================== test session starts ===============================\nplatform 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\ncachedir: .pytest_cache\nrootdir: /Users/god/PycharmProjects/pytest-parametrize-suite\nplugins: parametrize-suite-23.1.0, cov-4.0.0\ncollected 4 items                                                                 \n\nsrc/pytest_parametrize_suite/example.py::test_iso8601[datetime] PASSED      [ 25%]\nsrc/pytest_parametrize_suite/example.py::test_iso8601[date] PASSED          [ 50%]\nsrc/pytest_parametrize_suite/example.py::test_iso8601[time] PASSED          [ 75%]\nsrc/pytest_parametrize_suite/example.py::test_iso8601[timedelta] PASSED     [100%]\n\n================================ 4 passed in 0.02s ================================\n```\n\nAs you can see, we get a developer-friendly output for our parametrized tests while \nminimizing the amount of cognitive overhead it takes to understand and develop our test \ncases.\n\nHappy testing! :white_check_mark:\n",
    "bugtrack_url": null,
    "license": "GPL-3.0",
    "summary": "A simple pytest extension for creating a named test suite.",
    "version": "23.1.2",
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "055739f602d4af4f391976e355dc615cdbb0c2a18df1a44af8785d0b69ad49da",
                "md5": "f021078faa29ef6c77eeb1017d3fdffa",
                "sha256": "a3a6258cef97943c8e7321099e903a4f782dac1bb8416d7bef37b9ee334dca2f"
            },
            "downloads": -1,
            "filename": "pytest_parametrize_suite-23.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f021078faa29ef6c77eeb1017d3fdffa",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8.1,<4.0",
            "size": 18120,
            "upload_time": "2023-01-19T13:15:48",
            "upload_time_iso_8601": "2023-01-19T13:15:48.998069Z",
            "url": "https://files.pythonhosted.org/packages/05/57/39f602d4af4f391976e355dc615cdbb0c2a18df1a44af8785d0b69ad49da/pytest_parametrize_suite-23.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "98aca774673d4a26cd113c4b8e1b9c92a6ef11266db8bd6444be1c9d69c08794",
                "md5": "15106fb4add248e8da417104b048f277",
                "sha256": "f3e11143d38694e6ddc55876070018351c570df25ce45041eec590191a907d1f"
            },
            "downloads": -1,
            "filename": "pytest_parametrize_suite-23.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "15106fb4add248e8da417104b048f277",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8.1,<4.0",
            "size": 18129,
            "upload_time": "2023-01-19T13:15:51",
            "upload_time_iso_8601": "2023-01-19T13:15:51.084190Z",
            "url": "https://files.pythonhosted.org/packages/98/ac/a774673d4a26cd113c4b8e1b9c92a6ef11266db8bd6444be1c9d69c08794/pytest_parametrize_suite-23.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-01-19 13:15:51",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "lcname": "pytest-parametrize-suite"
}
        
Elapsed time: 0.08710s