From 6fec7f8d69027dfcdc6325357ebc90f466e88986 Mon Sep 17 00:00:00 2001 From: Bill Little Date: Fri, 6 Nov 2020 11:06:50 +0000 Subject: [PATCH] pytest and codecov (#9) * pytest config and restructure * codecov --- .cirrus.yml | 5 +++ .flake8 | 2 + esmf_regrid/tests/__init__.py | 40 ++++++++++++++++++- .../test_GridInfo/small_grid.txt | 0 esmf_regrid/tests/unit/__init__.py | 1 + .../esmf_regridder}/test_GridInfo.py | 12 +++--- noxfile.py | 34 ++++++++++------ pyproject.toml | 1 + setup.cfg | 9 +++++ 9 files changed, 85 insertions(+), 19 deletions(-) rename esmf_regrid/tests/results/{ => unit/esmf_regridder}/test_GridInfo/small_grid.txt (100%) create mode 100644 esmf_regrid/tests/unit/__init__.py rename esmf_regrid/tests/{ => unit/esmf_regridder}/test_GridInfo.py (80%) diff --git a/.cirrus.yml b/.cirrus.yml index cb7aa6ac..0c72be0f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -63,11 +63,15 @@ linux_task: PY_VER: "3.7" env: PY_VER: "3.8" + COVERAGE: "pytest-cov codecov" name: "Linux: py${PY_VER}" container: image: gcc:latest env: PATH: ${HOME}/miniconda/bin:${PATH} + CODECOV_TOKEN: "ENCRYPTED\ + [1ed538b97a8d005bdd5ab729de009ac38a2b53389edb0912\ + d2e76f5ce1e71c5f7bdea80a79492b57af54691c8936bdc7]" conda_cache: folder: ${HOME}/miniconda fingerprint_script: @@ -89,6 +93,7 @@ linux_task: fingerprint_script: - echo "${CIRRUS_OS} tests ${PY_VER}" - cat ${CIRRUS_WORKING_DIR}/requirements/py$(echo ${PY_VER} | tr -d ".").yml + - if [ -n "${COVERAGE}" ]; then echo "${COVERAGE}"; fi test_script: - nox --session tests diff --git a/.flake8 b/.flake8 index 995965af..1e0858a7 100644 --- a/.flake8 +++ b/.flake8 @@ -9,6 +9,7 @@ docstring-convention = numpy import-order-style = google +application-import-names = esmf_regrid select = C,D,E,F,I,W,B,B950 ignore = # E203: whitespace before ':' @@ -29,3 +30,4 @@ ignore = W504 exclude = esmf_regrid/__init__.py + esmf_regrid/tests/results diff --git a/esmf_regrid/tests/__init__.py b/esmf_regrid/tests/__init__.py index 03a5f602..15aac1e3 100644 --- a/esmf_regrid/tests/__init__.py +++ b/esmf_regrid/tests/__init__.py @@ -1 +1,39 @@ -"""Unit tests for esmf_regrid.""" +"""Common testing infrastructure.""" + +import pathlib + + +# Base directory of the test results. +_RESULT_PATH = pathlib.Path(__file__).parent.resolve() / "results" + + +def get_result_path(relative_path, unit=True): + """ + Form the absolute path to the results test file. + + Parameters + ---------- + relative_path : str, path, iterable str/path + The relative path to the target test file. + unit : bool, optional + Specify whether the `relative_path` is for a unit test. + Default is True. + + Returns + ------- + Path + The absolute result path. + + """ + if isinstance(relative_path, str): + relative_path = pathlib.Path(relative_path) + + if not isinstance(relative_path, pathlib.PurePath): + relative_path = pathlib.Path(*relative_path) + + if unit: + relative_path = pathlib.Path("unit") / relative_path + + result = _RESULT_PATH / relative_path + + return result.resolve(strict=True) diff --git a/esmf_regrid/tests/results/test_GridInfo/small_grid.txt b/esmf_regrid/tests/results/unit/esmf_regridder/test_GridInfo/small_grid.txt similarity index 100% rename from esmf_regrid/tests/results/test_GridInfo/small_grid.txt rename to esmf_regrid/tests/results/unit/esmf_regridder/test_GridInfo/small_grid.txt diff --git a/esmf_regrid/tests/unit/__init__.py b/esmf_regrid/tests/unit/__init__.py new file mode 100644 index 00000000..03a5f602 --- /dev/null +++ b/esmf_regrid/tests/unit/__init__.py @@ -0,0 +1 @@ +"""Unit tests for esmf_regrid.""" diff --git a/esmf_regrid/tests/test_GridInfo.py b/esmf_regrid/tests/unit/esmf_regridder/test_GridInfo.py similarity index 80% rename from esmf_regrid/tests/test_GridInfo.py rename to esmf_regrid/tests/unit/esmf_regridder/test_GridInfo.py index cef5f875..896c543a 100644 --- a/esmf_regrid/tests/test_GridInfo.py +++ b/esmf_regrid/tests/unit/esmf_regridder/test_GridInfo.py @@ -1,9 +1,9 @@ """Unit tests for :class:`esmf_regrid.esmf_regridder.GridInfo`.""" -import os +import numpy as np from esmf_regrid.esmf_regridder import GridInfo -import numpy as np +import esmf_regrid.tests as tests def _make_small_grid_args(): @@ -29,9 +29,9 @@ def test_make_grid(): esmf_grid = grid.make_esmf_field() esmf_grid.data[:] = 0 - relative_path = os.path.join("results", "test_GridInfo", "small_grid.txt") - abs_path = os.path.join(os.path.dirname(__file__), relative_path) - with open(abs_path) as file: - expected_repr = file.read() + relative_path = ("esmf_regridder", "test_GridInfo", "small_grid.txt") + fname = tests.get_result_path(relative_path) + with open(fname) as fi: + expected_repr = fi.read() assert esmf_grid.__repr__() == expected_repr diff --git a/noxfile.py b/noxfile.py index 629c8b1e..a115354d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -10,15 +10,18 @@ import nox -#: default to reusing any pre-existing nox environments. +#: Default to reusing any pre-existing nox environments. nox.options.reuse_existing_virtualenvs = True -#: name of the package to test. +#: Name of the package to test. PACKAGE = "esmf_regrid" -#: cirrus-ci environment variable hook. +#: Cirrus-CI environment variable hook. PY_VER = os.environ.get("PY_VER", "3.8") +#: Cirrus-CI environment variable hook. +COVERAGE = os.environ.get("COVERAGE", False) + @nox.session def lint(session): @@ -31,11 +34,11 @@ def lint(session): A `nox.sessions.Session` object. """ - # pip install the session requirements. + # Pip install the session requirements. session.install("flake8", "flake8-docstrings", "flake8-import-order") - # execute the flake8 linter on the package. + # Execute the flake8 linter on the package. session.run("flake8", PACKAGE) - # execute the flake8 linter on this file. + # Execute the flake8 linter on this file. session.run("flake8", __file__) @@ -50,11 +53,11 @@ def style(session): A `nox.sessions.Session` object. """ - # pip install the session requirements. + # Pip install the session requirements. session.install("black==20.8b1") - # execute the black format checker on the package. + # Execute the black format checker on the package. session.run("black", "--check", PACKAGE) - # execute the black format checker on this file. + # Execute the black format checker on this file. session.run("black", "--check", __file__) @@ -75,9 +78,9 @@ def tests(session): - https://github.com/theacodes/nox/issues/260 """ - # determine the conda requirements yaml file. + # Determine the conda requirements yaml file. fname = f"requirements/py{PY_VER.replace('.', '')}.yml" - # back-door approach to force nox to use "conda env update". + # Back-door approach to force nox to use "conda env update". command = ( "conda", "env", @@ -87,4 +90,11 @@ def tests(session): "--prune", ) session._run(*command, silent=True, external="error") - session.run("pytest", "-v", "./esmf_regrid/tests") + if COVERAGE: + # Execute the tests with code coverage. + session.conda_install("--channel=conda-forge", *COVERAGE.split()) + session.run("pytest", "--cov-report=xml", "--cov") + session.run("codecov") + else: + # Execute the tests. + session.run("pytest") diff --git a/pyproject.toml b/pyproject.toml index 38ebcd5f..6e9c4517 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ exclude = ''' | build | dist )/ + | results ) ''' diff --git a/setup.cfg b/setup.cfg index c53c62e8..0ec968fd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,3 +34,12 @@ python_requires = setup_requires = setuptools>=40.8.0 zip_safe = False + +[tool:pytest] +testpaths = + esmf_regrid/ +addopts = + -ra + -v + --doctest-modules +doctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS NUMBER