Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Testing in notebooks

Some useful references:

The ipytest module lets us run tests inside a notebook, which enables the gradual evolution of code from living in a notebook during interactive exploration, and then being moved to modules and packages as we modularize and abstract reusable parts, all while remaining tested.

In a notebook that we want to run tests for, we start by importing and configuring ipytest (the docs have more details on the various options):

import ipytest
ipytest.autoconfig()

If we have a collection of tests in a single cell, we can use the %%ipytest cell magic, provided by the package. Note that flag to ignore an annoying DeprecationWarning, it kicks in only the 2nd time we run the cell but helps keep the visual noise down.

%%ipytest -qq -W ignore::DeprecationWarning

# This test will pass
def test_addition():
    assert 1 + 1 == 2

# This one will fail
def test_problem():
    assert 1 + 1 == 3

# And we may want to have a test we don't run for now...
import pytest
@pytest.mark.skip(reason="no way of currently testing this")
def test_mystery():
    pass
.Fs                                                                                          [100%]
============================================= FAILURES =============================================
___________________________________________ test_problem ___________________________________________

    def test_problem():
>       assert 1 + 1 == 3
E       assert (1 + 1) == 3

/var/folders/j1/n8kn9ftd7257n2rvkkzlj3mc0010dw/T/ipykernel_39407/3734627355.py:7: AssertionError
===================================== short test summary info ======================================
FAILED t_de6dfc9099544e969c1912f0c3674ff3.py::test_problem - assert (1 + 1) == 3

The beauty of ipytest is that it can find tests defined anywhere in the notebook and run them:

ipytest.run('-W ignore::DeprecationWarning')
.Fs                                                                                          [100%]
============================================= FAILURES =============================================
___________________________________________ test_problem ___________________________________________

    def test_problem():
>       assert 1 + 1 == 3
E       assert (1 + 1) == 3

/var/folders/j1/n8kn9ftd7257n2rvkkzlj3mc0010dw/T/ipykernel_39407/3734627355.py:7: AssertionError
===================================== short test summary info ======================================
FAILED t_de6dfc9099544e969c1912f0c3674ff3.py::test_problem - assert (1 + 1) == 3
1 failed, 1 passed, 1 skipped in 0.01s
<ExitCode.TESTS_FAILED: 1>

If we define more tests now:

def test_bad():
    assert 1 == 0

def test_crash():
    1/0

They will also be found:

ipytest.run('-W ignore::DeprecationWarning')
.FsFF                                                                                        [100%]
============================================= FAILURES =============================================
___________________________________________ test_problem ___________________________________________

    def test_problem():
>       assert 1 + 1 == 3
E       assert (1 + 1) == 3

/var/folders/j1/n8kn9ftd7257n2rvkkzlj3mc0010dw/T/ipykernel_39407/3734627355.py:7: AssertionError
_____________________________________________ test_bad _____________________________________________

    def test_bad():
>       assert 1 == 0
E       assert 1 == 0

/var/folders/j1/n8kn9ftd7257n2rvkkzlj3mc0010dw/T/ipykernel_39407/714497975.py:2: AssertionError
____________________________________________ test_crash ____________________________________________

    def test_crash():
>       1/0
E       ZeroDivisionError: division by zero

/var/folders/j1/n8kn9ftd7257n2rvkkzlj3mc0010dw/T/ipykernel_39407/714497975.py:5: ZeroDivisionError
===================================== short test summary info ======================================
FAILED t_de6dfc9099544e969c1912f0c3674ff3.py::test_problem - assert (1 + 1) == 3
FAILED t_de6dfc9099544e969c1912f0c3674ff3.py::test_bad - assert 1 == 0
FAILED t_de6dfc9099544e969c1912f0c3674ff3.py::test_crash - ZeroDivisionError: division by zero
3 failed, 1 passed, 1 skipped in 0.01s
<ExitCode.TESTS_FAILED: 1>