.. _tutorial:
Tutorial
=========
In this section we present examples of setting up tests for workflow
managers. The examples start out from a simple setting adding
complexity with each subsection. The tests and example workflow files
can be found in the tests directory that ships with the package
distribution.
Snakemake workflow
-------------------
This section describes how to setup tests of a snakemake workflow. In
order to use the test fixtures with the `snakemake workflow manager
`_, we need to setup a
Snakefile and a test file.
The Snakefile defines rules that declare what to do with the input
data. In a real-life scenario, we would run various bioinformatics
applications to transform the input into some meaningful output. Here,
we perform operations using basic shell commands, but the same
principle applies to a bioinformatics workflow. The Snakefile in this
example looks as follows:
.. literalinclude:: ../pytest_ngsfixtures/tests/Snakefile
:language: python
Setting up a workflow with a predefined sample layout
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The test file `test_workflow_simple.py` defines a test `test_workflow`
that depends on the default
:py:data:`~pytest_ngsfixtures.plugin.samples` fixture. As the
Snakefile resides in the same directory, the
:py:data:`~pytest_ngsfixtures.wm.snakemake.snakefile` fixture will
automatically detect its presence and setup the file. If there is no
Snakefile present, the full path has to be passed with the `snakefile`
argument to `pytest.mark.snakefile`.
By default, fixtures are setup to copy files to the test directory. By
passing `copy=False` to the `pytest.mark` helpers, we use symlinks
instead. In addition, we pass the option `numbered=True` to generate
numbered output directories.
.. literalinclude::
../pytest_ngsfixtures/tests/test_workflow_simple.py
:language: python
The :py:func:`test_workflow` function requires the two fixtures
`samples` and `snakefile`, and the workflow is run with the
:py:func:`~pytest_ngsfixtures.snakemake.run` wrapper. Finally, we
assert that the test has run to completion by asserting the existence
of the output file `results.txt`. Now, the tests can be run with the
command
.. code-block:: shell
pytest -v -s tests/test_workflow_simple.py
Setting up a docker container fixture
+++++++++++++++++++++++++++++++++++++
In the following test script (`test_workflow_docker.py`), we
add functionality to deal with container-based fixtures.
First, we import the :py:mod:`docker` module to interact with docker,
along with :py:mod:`os` and :py:mod:`pytest`:
.. literalinclude:: ../pytest_ngsfixtures/tests/test_workflow_docker.py
:language: python
:lines: 2-4
Then, we add a `container` fixture that sets up a container based on
the snakemake docker image
`quay.io/biocontainers/snakemake:X.Y.Z--py36_0
`_,
where `X.Y.Z` corresponds to the installed snakemake version:
.. literalinclude:: ../pytest_ngsfixtures/tests/test_workflow_docker.py
:language: python
:lines: 8-33
Finally, we add the `container` fixture to the test function call:
.. literalinclude:: ../pytest_ngsfixtures/tests/test_workflow_docker.py
:language: python
:lines: 36-45
and run the test as
.. code-block:: shell
pytest -v -s tests/test_workflow_docker.py
Parametrized tests on running environment
++++++++++++++++++++++++++++++++++++++++++
We have now written tests for local execution and execution in a
container. By parametrizing the tests, we can combine the two cases in
one test function. To do this we modify the test function as follows
(see `test_workflow_parametrize.py`):
.. literalinclude:: ../pytest_ngsfixtures/tests/test_workflow_parametrize.py
:language: python
:lines: 38-49
The parametrization is done indirectly via the `container` fixture. We
modify this fixture to return `None` if the request parameter equals
`local`, and if the parameter equals `docker` we return the container:
.. literalinclude:: ../pytest_ngsfixtures/tests/test_workflow_parametrize.py
:language: python
:lines: 8-35
Now, running
.. code-block:: shell
pytest -v -s tests/test_workflow_parametrize.py
will execute two tests, one for the local environment, one in the
docker container.