55

I'm working on a presentation about python testing options, and one of the technologies I want to demo is pytest. I'm planning to do the presentation from an jupyter/ipython notebook. Ideally I'd like to be able to define a test function in a cell and then use pytest to run just that function; that way I can demonstrate individual features of pytest, etc.

Is there an existing way to do this? None of the interactive features I saw in the pytest api seem to fit the bill, but I'm certainly no pytest expert. I'd be happy to write a plugin to do it, so any advice on the best approach in that direction would be great.

I did see pytest-ipynb, but it does not seem to do what I need. If that assessment is wrong, advice on how to use that would be great, too.

abingham
  • 1,294
  • 1
  • 10
  • 17
  • Just to add to the data here, but not actually answer the question, there is https://github.com/computationalmodelling/nbval – Russel Winder Jan 30 '17 at 10:16

4 Answers4

30

There is a similar module that looks very mature: https://github.com/chmp/ipytest

It is referenced in the module developed by @akaiola and is more active and regularly updated / maintained.

In particular, the tests could use some functions defined in other cells, which is the whole purpose of performing tests inside the Notebook (see example below).

To use it:

  1. Put in a cell an import and configuration of ipytest:
import ipytest
ipytest.autoconfig()
  1. Write some tests in cell(s)
  2. Either run cells with test with %%ipytest magic for each cell with test ... or put a ipytest.run() in a cell after the tests

You can check the official example: https://github.com/chmp/ipytest/blob/main/Example.ipynb

Or an example I did:

example 1

And another example:

another example

Jean-Francois T.
  • 11,549
  • 7
  • 68
  • 107
  • Also - one can use the `%%writefile` magic, then call `!pytest` - demonstrated in [this talk by Florian Bruhin](https://bruhin.software/ins-pytest/). – Yinon Ehrlich Aug 15 '23 at 07:16
  • @YinonEhrlich Interesting addition. However, this would be limited if we want to test functions defined in other cells of your notebook... unless you duplicate writing of this code as well. – Jean-Francois T. Aug 16 '23 at 07:22
22

I created ipython_pytest for this purpose and used it in my PyCon Helsinki 2016 presentation.

You would use the tool like this:

%%pytest

def test_my_stuff():
    assert 42 == 42

Unfortunately I couldn't find a way to make functions and classes defined in the notebook available to test functions in the test cell. I'd appreciate if someone comes up with a solution for that.

akaihola
  • 26,309
  • 7
  • 59
  • 69
6

My 2 cents here since I've already solved this issue for myself 2x and both times come back to this site. For my future self:

For a project structured in the following way

prod_folder:
* data
* code
    * run_notebook.ipynb
* tests
   * test_some_test.py

If you want to run pytest from within run_notebook.ipynb the following cell-magic worked for my purposes:

!pytest ../tests
Aus_10
  • 670
  • 7
  • 15
3

In Google Colab I usually do the following procedure:

  1. Create a file name for the respective cell:

Here's an example:

%%file test_list.py

# find the mismatched elements in list `l1` which are not in list `l2`

def solution(l1: list, l2: list) -> list:
    return [
        e
        for e in l1
        if e not in [e for e in l2]
    ]

import pytest

a = [1,2,3]
b = [3,4,None,None]
TEST_CASES = [[a,b]]

class TestCase:
    @pytest.mark.parametrize("test_case", TEST_CASES)
    def test_events(self, test_case):
        assert solution(test_case[0], test_case[1]) == [1,2]
  1. Run pytest in another cell:
!python -m pytest test_list.py 

Out:

============================= test session starts ==============================
platform linux -- Python 3.8.16, pytest-3.6.4, py-1.11.0, pluggy-0.7.1
rootdir: /content, inifile:
plugins: typeguard-2.7.1
collected 1 item                                                               

test_list.py .                                                           [100%]

=========================== 1 passed in 0.02 seconds ===========================
Benyamin Jafari
  • 27,880
  • 26
  • 135
  • 150