Repository: popsim-consortium/stdpopsim (language: python)

Issue:
change CI tests to use pytest instead of nose
[Nose](https://github.com/nose-devs/nose/) is unmaintained (last release is from 2015), and [pytest](https://docs.pytest.org/en/stable/) has a raft of improvements. There's no need to change to using pytest-specific features en mass---we should just start by changing the CI and dev docs.


Discussion / hints:

Fix patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 6b8a4f842..a1bd62cfc 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -31,6 +31,10 @@ jobs:
             git clone --bare https://github.com/MesserLab/SLiM /tmp/SLiM_top/SLiM
             cd /tmp/SLiM_top/SLiM
             git describe --tags $(git rev-list --tags --max-count=1) > ${TAG_FILE}
+            # FIXME Pinning to SLiM 3.5 for now; looks like there's an issue with 3.6
+            echo v3.5 > ${TAG_FILE}
+            echo Using SLiM version $(cat /tmp/SLiM_tag)
+
       - restore_cache:
           key: SLiM-v2-{{ checksum "/tmp/SLiM_tag" }}
       - run:
@@ -117,9 +121,6 @@ jobs:
 
   test:
     <<: *container_config
-    environment:
-      XML_RESULTS_DIR: xml
-      XML_RESULTS: xml/results.xml
     parallelism: 3
     steps:
       - *set_py_circleci_own
@@ -130,10 +131,8 @@ jobs:
       - run:
           name: Run Python tests
           command: |
-            mkdir -p ${XML_RESULTS_DIR}
-            nosetests -vs --with-coverage --cover-package stdpopsim \
-              --cover-branches --cover-erase --cover-xml --with-xunit --xunit-file=${XML_RESULTS} \
-              --cover-inclusive $(circleci tests glob "tests/*.py" | circleci tests split --split-by=timings --timings-type=classname)
+            pytest --cov=stdpopsim -cov-report=term-missing --cov-report=xml \
+              --cov-branch tests
       - codecov/upload:
           file: coverage.xml
       - store_test_results:
diff --git a/docs/development.rst b/docs/development.rst
index b5ad6d2e2..cc52f0557 100644
--- a/docs/development.rst
+++ b/docs/development.rst
@@ -1100,11 +1100,14 @@ It is not practical to test the statistical properties of simulation models
 as part of unit tests.
 
 The unit test suite is in the ``tests`` directory. Tests are run using the
-`nose <https://nose.readthedocs.io/en/latest/>`_ module. Use::
+`pytest <https://docs.pytest.org/en/stable/>`_ module. Use::
 
-    $ python3 -m nose tests/
+    $ python3 -m pytest
 
-from the project root to run the full test suite.
+from the project root to run the full test suite. Pytest is very powerful and
+has lots of options; please see the `tskit documentation
+<https://tskit.dev/tskit/docs/stable/development.html#tests>`_ for help on
+how to run pytest and some common options.
 
 It's useful to run the ``flake8`` CI tests *locally* before pushing a commit.
 To set this up use either ``pip`` or ``conda`` to install ``flake8``
diff --git a/requirements/CI/requirements.txt b/requirements/CI/requirements.txt
index cf4c3787d..797c09000 100644
--- a/requirements/CI/requirements.txt
+++ b/requirements/CI/requirements.txt
@@ -1,7 +1,9 @@
 codecov==2.1.11
 coverage==5.5
 flake8==3.8.4
-nose==1.3.7
+pytest==6.2.2
+pytest-cov==2.10.1
+pytest-xdist==2.2.0
 setuptools-scm==5.0.1
 sphinx==3.5.1
 sphinx-argparse==0.2.5
diff --git a/requirements/development.txt b/requirements/development.txt
index cd6a06371..5e2c653f9 100644
--- a/requirements/development.txt
+++ b/requirements/development.txt
@@ -3,7 +3,9 @@ blacken-docs
 codecov
 coverage
 flake8
-nose
+pytest
+pytest-cov
+pytest-xdist
 setuptools_scm
 sphinx
 sphinx-argparse


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index c82d68171..f6b698b69 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -77,10 +77,10 @@ jobs:
       - name: install dependencies
         if: steps.cache.outputs.cache-hit != 'true'
         run: |
+          conda install --yes --file=requirements/CI/conda.txt
           # Install pre-release from non standard label until msprime
           # 1.0 is tagged.
-          conda install -c conda-forge/label/mprime_rc -c conda-forge msprime
-          conda install --yes --file=requirements/CI/conda.txt
+          conda install -c conda-forge/label/msprime_rc msprime
           if [ "$RUNNER_OS" != "Windows" ]; then
             conda install --yes slim==${{ env.SLIM_TAG }}
           fi
@@ -88,5 +88,5 @@ jobs:
 
       - name: run test suite
         run: |
-          nosetests -v --with-coverage --cover-package stdpopsim tests
+          pytest -n0 --cov=stdpopsim --cov-branch tests
           coverage report -m
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 000000000..50b8418b9
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,4 @@
+[pytest]
+addopts = -n 4
+testpaths =
+    tests