# Common Patterns for Tests¶

In this section you will learn some useful features of pytest that can make your tests succinct and easy to maintain.

## Parametrized Tests¶

Tests that apply the same general test logic to a collection of different parameters can use parametrized tests. For example, this:

import numpy as np
from ..refraction import snell

def test_perpendicular():
# For any indexes, a ray normal to the surface should not bend.
# We'll try a couple different combinations of indexes....

actual = snell(0, 2.00, 3.00)
expected = 0
assert actual == expected

actual = snell(0, 3.00, 2.00)
expected = 0
assert actual == expected


can be rewritten as:

import numpy as np
import pytest
from ..refraction import snell

@pytest.mark.parametrize('n1, n2',
[(2.00, 3.00),
(3.00, 2.00),
])
def test_perpendicular(n1, n2):
# For any indexes, a ray normal to the surface should not bend.
# We'll try a couple different combinations of indexes....

actual = snell(0, n1, n2)
expected = 0
assert actual == expected


The string 'n1, n2' specifies which parameters this decorator will fill in. Pytest will run test_perpendicular twice, one for each entry in the list [(2.00, 3.00), (3.00, 2.00)], passing in the respective values n1 and n2 as arguments.

From here we refer you to the pytest parametrize documentation.

## Fixtures¶

Tests that have different logic but share the same setup code can use pytest fixtures. For example, this:

import numpy as np

def test_height():
# Construct a 1-dimensional Gaussian peak.
x = np.linspace(-10, 10, num=21)
sigma = 3.0
peak = np.exp(-(x / sigma)**2 / 2) / (sigma * np.sqrt(2 * np.pi))
expected = 1 / (sigma * np.sqrt(2 * np.pi))
# Test that the peak height is correct.
actual = np.max(peak)
assert np.allclose(actual, expected)

def test_nonnegative():
# Construct a 1-dimensional Gaussian peak.
x = np.linspace(-10, 10, num=20)
sigma = 3.0
peak = np.exp(-(x / sigma)**2 / 2) / (sigma * np.sqrt(2 * np.pi))
# Test that there are no negative values.
assert np.all(peak >= 0)


can be written as:

import pytest
import numpy as np

@pytest.fixture
def peak():
# Construct a 1-dimensional Gaussian peak.
x = np.linspace(-10, 10, num=21)
sigma = 3.0
peak = np.exp(-(x / sigma)**2 / 2) / (sigma * np.sqrt(2 * np.pi))
return peak

def test_height(peak):
expected = 1 / (sigma * np.sqrt(2 * np.pi))
# Test that the peak height is correct.
actual = np.max(peak)
assert np.allclose(actual, expected)

def test_nonnegative(peak):
# Test that there are no negative values.
assert np.all(peak >= 0)


To reuse a fixture in multiple files, add it to conftest.py located in the tests/ directory. It will automatically be imported by pytest into each test module.

From here we refer you to the pytest fixtures documentation.

## Skipping Tests¶

Sometimes it is useful to skip specific tests under certain conditions. Examples:

import pytest
import sys

@pytest.mark.skipif(sys.version_info < (3, 7),
reason="requires python3.7 or higher")
def test_something():
...

@pytest.mark.skipif(sys.platform == 'win32',
reason="does not run on windows")
def test_something_that_does_not_work_on_windows():
...

def test_something_that_needs_a_special_dependency():
some_library = pytest.importorskip("some_library")
...


From here we refer you to the pytest skipping documentation.