\( \newcommand{\NOT}{\neg} \newcommand{\AND}{\wedge} \newcommand{\OR}{\vee} \newcommand{\XOR}{\oplus} \newcommand{\IMP}{\Rightarrow} \newcommand{\IFF}{\Leftrightarrow} \newcommand{\TRUE}{\text{True}\xspace} \newcommand{\FALSE}{\text{False}\xspace} \newcommand{\IN}{\,{\in}\,} \newcommand{\NOTIN}{\,{\notin}\,} \newcommand{\TO}{\rightarrow} \newcommand{\DIV}{\mid} \newcommand{\NDIV}{\nmid} \newcommand{\MOD}[1]{\pmod{#1}} \newcommand{\MODS}[1]{\ (\text{mod}\ #1)} \newcommand{\N}{\mathbb N} \newcommand{\Z}{\mathbb Z} \newcommand{\Q}{\mathbb Q} \newcommand{\R}{\mathbb R} \newcommand{\C}{\mathbb C} \newcommand{\cA}{\mathcal A} \newcommand{\cB}{\mathcal B} \newcommand{\cC}{\mathcal C} \newcommand{\cD}{\mathcal D} \newcommand{\cE}{\mathcal E} \newcommand{\cF}{\mathcal F} \newcommand{\cG}{\mathcal G} \newcommand{\cH}{\mathcal H} \newcommand{\cI}{\mathcal I} \newcommand{\cJ}{\mathcal J} \newcommand{\cL}{\mathcal L} \newcommand{\cK}{\mathcal K} \newcommand{\cN}{\mathcal N} \newcommand{\cO}{\mathcal O} \newcommand{\cP}{\mathcal P} \newcommand{\cQ}{\mathcal Q} \newcommand{\cS}{\mathcal S} \newcommand{\cT}{\mathcal T} \newcommand{\cV}{\mathcal V} \newcommand{\cW}{\mathcal W} \newcommand{\cZ}{\mathcal Z} \newcommand{\emp}{\emptyset} \newcommand{\bs}{\backslash} \newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor} \newcommand{\ceil}[1]{\left \lceil #1 \right \rceil} \newcommand{\abs}[1]{\left | #1 \right |} \newcommand{\xspace}{} \newcommand{\proofheader}[1]{\underline{\textbf{#1}}} \)

B.2 pytest

pytest is a Python library used to run tests for your code. In this section, we’ll describe how to write tests that are automatically discovered and run by pytest, how to actually run pytest in your code, and some tips and tricks for making the most of pytest.

How do you write a pytest test?

A test in pytest is a Python function whose name starts with test_. Inside a test function, we use assert statements to verify expected values or behaviours of a function.

For example:

# This is the function to test
def has_more_trues(booleans: list) -> bool:
    """Return whether booleans contains more True values than False values.

    >>> has_more_trues([True, False, True])
    True
    >>> has_more_trues([True, False, False])
    False
    """
    # Function body omitted


# This the test
def test_mixture_one_more_true() -> None:
    """Test has_more_trues on a list with a mixture of True and False,
    with one more True than False.
    """
    assert has_more_trues([True, False, True])

A single test can have multiple assert statements, although it is generally recommended to separate each assert statement into a separate test. A single Python file can have multiple tests; when pytest is run on a file, it (by default) runs all the tests in that file.

Running pytest

The simplest way of running pytest is to add the following if __name__ == '__main__' block to the bottom of a test file:

if __name__ == '__main__':
    import pytest
    pytest.main()

When you run this file, pytest.main will run all test functions in the file. Note: by default, pytest.main actually searches through all Python files in the current directory whose name starts with test_ or ends with _test, which can be a bit surprising. So our practice will be to explicitly pass in the name of the current test file to pytest.main, wrapped in a list:

# If we're in a file test_my_file.py

if __name__ == '__main__':
    import pytest
    pytest.main(['test_my_file.py'])

Testing for an exceptions

It is possible to write a pytest test that checks whether a function raises a specific error. To do so, use pytest.raises, which takes an error type as an argument, inside a with statement. Here is an example

import pytest


def add_one(n: int) -> int:
    return n + 1


def test_add_one_type_error() -> None:
    """Test add_one when given a non-numeric argument."""
    with pytest.raises(TypeError):
        add_one('hello')

Options for pytest.main

pytest.main takes a list of strings as an argument because users can add options (as strings) to modify pytest’s default behaviour when running tests. The format for this is pytest.main([<option1>, <option2>, ...]).

Here are some useful options:

References

For the full documentation for the pytest library, check out https://docs.pytest.org/en/latest/.