Skip to content


Pytest and a Summary of a Gentle Introduction to Pytest#

  • A test is code that executes code.
  • You can define your requirements as code
  • Documenting the implementation
  • Continuously testing and ensuring it does not regress

Test Cases#

Say we want to validate email addresses with:

def is_valid_email(email):

A test case would be an example:


Lets Install pytest and test or function…


Install pytest

pip install pytest

Naming of Tests#

  • Your test functions need to be of the form * or test_*.py, with or without the underscore.
  • Your test class needs to start with Test, it seems like pytest discourages using classes

Strangely the class needn’t inherit from a pytest test case.


class TestClient(object):

    def test_one(self):
        x = "this"
        assert 'h' in x

    def test_two(self):
        x = "hello"
        assert hasattr(x, 'startswith')

Test Cases#


from validators import is_valid_email_address

def test_regular_email_validates():
    assert is_valid_email_address('')
    assert is_valid_email_address('')
    assert is_valid_email_address('')

def test_valid_email_has_one_at_sign():
    assert not is_valid_email_address('john.doe')

def test_valid_email_has_only_allowed_chars():
    assert not is_valid_email_address('john,')
    assert not is_valid_email_address('not')

Now run pytest

$ pytest
================================================================= test session starts =================================================================
platform darwin -- Python 3.9.9, pytest-7.1.0, pluggy-1.0.0
collected 3 items ...                                                                                                                               [100%]

================================================================== 3 passed in 0.01s ==================================================================

Add a few more tests:

def test_valid_email_can_have_plus_sign():
    assert is_valid_email_address('')

def test_valid_email_must_have_a_tld():
    assert not is_valid_email_address('john.doe@example')

Remember pytest only uses assert there are no intense assertions like in unittest

Writing tests first based on requirements it called Test Driven Development


In django fixtures are a term used for intial data to be loaded into the db. In pytest, fixtures refer to functions run before and after tests.

We can create these functions with the @pytest.fixture() decorator

import pytest

def database_environment():
  • yield indicates where pytest runs the tests
  • To use the fixture it must be added as an argument to the function

    def test_world(database_environment): assert 1 == 1

You can also get data from fixtures:

import pytest

def my_fruit():
    return "apple"

def test_fruit(my_fruit):
    assert my_fruit == "apple"

Configuration Files#

Pytest can read project specific config files:

  • pytest.ini
  • tox.ini
  • setup.cfg

In pytest.ini and tox.ini:

addopts = ​-rsxX -l --tb=short --strict​

In setup.cfg:

addopts = ​-rsxX -l --tb=short --strict​

There can be a file shared between tests - for common fixtures. It is also a good place to set the PATH, plugins and modifiers.


Running a single test#
List all the tests#
pytest --collect-only
Exit on the first error#
pytest -x
Run the last failed test#
pytest --lf
Show value of local values in output#
pytest -l
Using Python Debugger (pdb)#

pdb is a command line debugger built into Python. You can pytest to debug your test function’s code.

To drop into pdb after an exception (not very useful):

pytest --pdb

To begin a trace at the start of the last test that failed:

pytest --lf --trace