Supprimer Rendre public Rendre privé Add tags Delete tags
  Ajouter un tag   Annuler
  Supprimer le tag   Annuler
  • • DevOps notes •
  •  
  • AI
  • Tags
  • Connexion

Parametrized Tests/shaare/0k7HqQ

  • python
  • python

Parametrized Tests

Introduction

  • Often, we need to test the same logic with different inputs and outputs, such as validating various IP address or hostname formats.
  • Writing individual test functions for each case leads to repetitive code and a test suite that is harder to maintain.
  • Parametrized tests allow a single test function to run multiple times with different data, adhering to the DRY principle and simplifying test maintenance.

The Problem: Duplicated Test Logic

  • A function that checks valid hostname character codes must be tested across letters, digits, hyphens, and invalid symbols.
  • Without parametrization, each input case requires its own test function, duplicating the assertion logic.
  • This approach increases verbosity and makes the test suite more error-prone and tedious to update.

Solution: @pytest.mark.parametrize

  • The @pytest.mark.parametrize(argnames, argvalues) decorator takes argument names and a list of value tuples to generate multiple test invocations.
  • Argument names can be provided as a comma-separated string or as a list of strings.
  • Each tuple in the argvalues list corresponds to a separate run of the test function, with tuple elements mapped to argument names.
  • Running Pytest with -v shows each parametrized case as a distinct test, simplifying result interpretation.

The pytest.param Construct

  • The pytest.param() function wraps a set of parameter values and allows you to attach metadata to that invocation:
    • id: a custom label shown in the test report.
    • marks: one or more markers (e.g., pytest.mark.xfail, pytest.mark.skip) applied only to that case.
  • This is useful when you want to:
    • Give human-readable names to complex or ambiguous parameter sets.
    • Mark individual cases as expected failures or skip them selectively.

Customizing Test IDs

  • By default, Pytest creates IDs from parameter values, which may be non-descriptive for complex data.
  • You can use pytest.param(..., id="custom_id") to assign clear, human-readable names to individual cases.
  • Alternatively, an ids list passed to parametrize can specify identifiers in the order of argvalues.
  • Custom IDs make it easier to identify failing cases in test reports and improve overall readability.
import pytest

def is_valid_hostname_char(char: str) -> bool:
    if "a" <= char <= "z":
        return True
    if "0" <= char <= "9":
        return True
    if char == "-":
        return True
    return False

def check_url_status(url: str) -> tuple[int | str, str]:
    if url == "https://google.com":
        return (200, "OK")
    if url == "https://fakesite123.org/notfound":
        return (404, "HTTP_ERROR (404)")
    if url == "http://httpbin.org/status/503":
        return (503, "HTTP_ERROR (503)")
    if url == "http://localhost:1":
        return ("CONNECTION_ERROR", "CONNECTION_ERROR")
    return ("UNKNOWN", "UNKNOWN")

# Section: The Problem: Duplicated Test Logic

"""
a -> True
5 -> True
- -> True
A -> False
_ -> False
"""

def test_is_valid_lower_case_a():
    assert is_valid_hostname_char("a") is True

def test_is_valid_5():
    assert is_valid_hostname_char("5") is True

def test_is_valid_hyphen():
    assert is_valid_hostname_char("-") is True

def test_is_valid_upper_case_A():
    assert is_valid_hostname_char("A") is False

def test_is_valid_underscore():
    assert is_valid_hostname_char("_") is False

# Section: Solution: @pytest.mark.parametrize

@pytest.mark.parametrize(
    "input_char, expected_result",
    [
        ("a", True),
        ("5", True),
        ("-", True),
        ("A", False),
        ("_", False),
        ("!", False),
    ],
)
def test_is_valid_hostname_char(
    input_char: str, expected_result: bool
):
    assert is_valid_hostname_char(input_char) is expected_result

# Section: Customizing Test IDs with pytest.param construct

@pytest.mark.parametrize(
    "input_char, expected_result",
    [
        pytest.param("a", True, id="lowercase_letter_a"),
        pytest.param("z", True, id="lowercase_letter_z"),
        pytest.param("0", True, id="digit_0"),
        pytest.param("-", True, id="hyphen"),
        pytest.param("A", False, id="uppercase_A_invalid"),
        pytest.param("_", False, id="underscore_invalid"),
    ],
)
def test_is_valid_hostname_custom_params(
    input_char: str, expected_result: bool
):
    assert is_valid_hostname_char(input_char) is expected_result

@pytest.mark.parametrize(
    "url_to_check, expected_status_code, expected_status_text",
    [
        ("https://google.com", 200, "OK"),
        (
            "https://fakesite123.org/notfound",
            404,
            "HTTP_ERROR (404)",
        ),
        (
            "http://httpbin.org/status/503",
            503,
            "HTTP_ERROR (503)",
        ),
        (
            "http://localhost:1",
            "CONNECTION_ERROR",
            "CONNECTION_ERROR",
        ),
        pytest.param(
            "https://pending.retries.tests",
            503,
            "HTTP_ERROR (503)",
            marks=(
                pytest.mark.xfail(
                    reason="Retry logic for 503 is not yet implemented."
                ),
                pytest.mark.api,
            ),
        ),
    ],
    ids=[
        "google_ok",
        "site_not_found",
        "server_error_503",
        "connection_error",
        "xfail_retry_case",
    ],
)
def test_various_url_statuses(
    url_to_check: str,
    expected_status_code: int,
    expected_status_text: str,
):
    status_code, status_text = check_url_status(url_to_check)
    assert status_code == expected_status_code
    assert status_text == expected_status_text
1 month ago Permalien
cluster icon
  • Generators and Lazy Pipelines : Generators and Lazy Pipelines You can chain generator functions to form multi-stage data pipelines that process items one at a time. No intermediat...
  • Mocking : Mocking Fundamentals Introduction When unit testing DevOps scripts that interact with external systems, tests can become slow, unreliable, difficult ...
  • Dictionaries : Dictionaries (dict) Dictionaries are mutable, insertion-ordered collections of key-value pairs. Keys must be unique and immutable; values can be of an...
  • Variables, comments : Variables: Naming Values Naming Guidelines: Must start with a letter or underscore (_) and can contain letters, numbers, and underscores. Use snake_...
  • Handling Authentication : Handling Authentication APIs often require authentication to control access, rate limits, and auditing. Without authentication, requests to protected...


(110)
Filtrer par liens sans tag
Replier Replier tout Déplier Déplier tout Êtes-vous sûr de vouloir supprimer ce lien ? Êtes-vous sûr de vouloir supprimer ce tag ? Le gestionnaire de marque-pages personnel, minimaliste, et sans base de données par la communauté Shaarli