From c30567d2a12e5b80631408d450353e4ffde9cb98 Mon Sep 17 00:00:00 2001 From: Wei Ji Date: Tue, 27 Nov 2018 11:06:56 +1300 Subject: [PATCH] :art: Pair and lint test_ipynb notebook using jupytext and black Only a few newlines added to the actual code with black linter. This notebook/script pairing almost goes without saying. But I do wonder if I can simplify the _load_ipynb_modules function in environment.py now that we have paired notebooks. --- test_ipynb.ipynb | 16 +++++++-- test_ipynb.py | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 test_ipynb.py diff --git a/test_ipynb.ipynb b/test_ipynb.ipynb index c9f4791..2def81a 100644 --- a/test_ipynb.ipynb +++ b/test_ipynb.ipynb @@ -19,7 +19,9 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "from features.environment import _load_ipynb_modules\n", @@ -29,6 +31,7 @@ "import os\n", "import sys\n", "\n", + "\n", "def _unit_test_ipynb(path: str):\n", " \"\"\"\n", " Unit tests on loaded modules from a .ipynb file.\n", @@ -41,6 +44,7 @@ " if num_failures > 0:\n", " sys.exit(num_failures)\n", "\n", + "\n", "def _integration_test_ipynb(path: str, summary: bool = False):\n", " \"\"\"\n", " Integration tests on various feature behaviours inside a .feature file.\n", @@ -64,7 +68,6 @@ "metadata": {}, "source": [ "## Unit tests\n", - "\n", "Uses [doctest](https://en.wikipedia.org/wiki/Doctest).\n", "Small tests for each individual function." ] @@ -450,6 +453,15 @@ } ], "metadata": { + "jupytext": { + "formats": "ipynb,py:percent", + "text_representation": { + "extension": ".py", + "format_name": "percent", + "format_version": "1.2", + "jupytext_version": "0.8.6rc0" + } + }, "kernelspec": { "display_name": "deepbedmap", "language": "python", diff --git a/test_ipynb.py b/test_ipynb.py new file mode 100644 index 0000000..59bd1c6 --- /dev/null +++ b/test_ipynb.py @@ -0,0 +1,87 @@ +# --- +# jupyter: +# jupytext: +# formats: ipynb,py:percent +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.2' +# jupytext_version: 0.8.6rc0 +# kernelspec: +# display_name: deepbedmap +# language: python +# name: deepbedmap +# --- + +# %% [markdown] +# # Behavioural Driven Development Testing for Jupyter Notebooks +# +# Handy way to process the run unit tests (via doctest) and integration tests (via behave) in jupyter notebooks (.ipynb) containing Python functions. +# The script will convert an .ipynb to a string format (basically a .py file), loads them as modules, and runs the tests on them. +# To run it in the console, do: +# +# python -m pytest --verbose --disable-warnings --nbval test_ipynb.ipynb +# +# The script should tell you which ipynb file's doctests has failed (e.g. srgan_train.ipynb). +# You can then open up this very jupyter notebook to debug and inspect the situation further. + +# %% +from features.environment import _load_ipynb_modules +import behave.__main__ + +import doctest +import os +import sys + + +def _unit_test_ipynb(path: str): + """ + Unit tests on loaded modules from a .ipynb file. + Uses doctest. + """ + assert path.endswith(".ipynb") + + module = _load_ipynb_modules(ipynb_path=path) + num_failures, num_attempted = doctest.testmod(m=module, verbose=True) + if num_failures > 0: + sys.exit(num_failures) + + +def _integration_test_ipynb(path: str, summary: bool = False): + """ + Integration tests on various feature behaviours inside a .feature file. + Uses behave. + """ + assert os.path.exists(path=path) + assert path.endswith(".feature") + + if summary == False: + args = f"--tags ~@skip --no-summary {path}" + elif summary == True: + args = f"--tags ~@skip {path}" + + num_failures = behave.__main__.main(args=args) + if num_failures > 0: + sys.exit(num_failures) + + +# %% [markdown] +# ## Unit tests +# Uses [doctest](https://en.wikipedia.org/wiki/Doctest). +# Small tests for each individual function. + +# %% +_unit_test_ipynb(path="data_prep.ipynb") + +# %% +_unit_test_ipynb(path="srgan_train.ipynb") + +# %% [markdown] +# ## Integration tests +# +# Uses [behave](https://github.com/behave/behave). +# Medium sized tests which checks that components work together properly. +# Ensures that the behaviour of features (made up of units) is sound. + +# %% +_integration_test_ipynb(path="features/data_prep.feature")