Skip to content

Commit 9d7ef13

Browse files
authored
Enh: Add tests pages - run tests in ci and locally to guide
2 parents 518d937 + 0d28e06 commit 9d7ef13

File tree

6 files changed

+388
-8
lines changed

6 files changed

+388
-8
lines changed
30.6 KB
Loading

conf.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@
104104
"show_toc_level": 1,
105105
# "navbar_align": "left", # [left, content, right] For testing that the navbar items align properly
106106
"github_url": "https://github.com/pyopensci/python-package-guide",
107-
108107
"footer_start": ["copyright"],
109108
"footer_end": [],
110109
}
@@ -148,4 +147,7 @@
148147

149148
# Social cards
150149
ogp_site_url = "https://www.pyopensci.org/python-package-guide/"
151-
ogp_image = "_static/pyopensci-python-package-guide.png"
150+
ogp_social_cards = {
151+
"line_color": "#6D597A",
152+
"image": "_static/pyopensci-logo-package-guide.png",
153+
}

index.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,24 +133,26 @@ Learn about best practices for:
133133
::::
134134

135135
::::{grid-item}
136-
:::{card} ✨ Tests ✨
136+
:::{card} ✨ Tests for your Python package
137137
:class-card: left-aligned
138138

139139
* [Intro to testing](tests/index.md)
140-
* [Write tests](tests/write-tests.md)
141-
* [Types of tests](tests/test-types.md)
140+
* [Write tests](tests/write-tests)
141+
* [Types of tests](tests/test-types)
142+
* [Run tests locally](tests/run-tests)
143+
* [Run tests in CI](tests/tests-ci)
142144

143145
*We are actively working on this section. [Follow development here.](https://github.com/pyOpenSci/python-package-guide)*
144146
:::
145147
::::
146148

147149
::::{grid-item}
148-
:::{card} ✨ Code checks & clean code
150+
:::{card} ✨ Code style & Format
149151
:class-card: left-aligned
152+
:link: CONTRIBUTING
153+
:link-type: doc
150154

151155
* [Code style](package-structure-code/code-style-linting-format.md)
152-
153-
*We are actively working on this section. [Follow development here.](https://github.com/pyOpenSci/python-package-guide)*
154156
:::
155157
::::
156158

tests/index.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,29 @@ package: unit tests, integration tests and end-to-end (or functional) tests. Lea
3636
:::
3737
::::
3838

39+
::::{grid-item}
40+
:::{card} ✨ Run tests locally ✨
41+
:link: test-types
42+
:link-type: doc
43+
:class-card: left-aligned
44+
45+
If you expect your users to use your package across different versions
46+
of Python, then using an automation tool such as nox to run your tests is useful. Learn about the various tools that you can use to run your tests across python versions here.
47+
:::
48+
::::
49+
50+
::::{grid-item}
51+
:::{card} ✨ Run tests online (using CI) ✨
52+
:link: test-types
53+
:link-type: doc
54+
:class-card: left-aligned
55+
56+
Continuous integration platforms such as GitHub actions can be
57+
useful for running your tests across both different Python versions
58+
and different operating systems. Learn about setting up tests to run in Continuous Integration here.
59+
:::
60+
::::
61+
3962
:::::
4063

4164

@@ -54,4 +77,6 @@ Graphic showing the elements of the packaging process.
5477
Intro <self>
5578
Write tests <write-tests>
5679
Test types <test-types>
80+
Run tests locally <run-tests>
81+
Run tests online (using CI) <tests-ci>
5782
```

tests/run-tests.md

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
```{eval-rst}
2+
:og:description: Learn how to setup and run tests for your Python package locally on your computer using automation tools such as Nox. Also learn about other tools that scientific Python community members use to run tests.
3+
:og:title: Run tests for your Python package across Python versions
4+
```
5+
6+
# Run Python package tests
7+
8+
Running your tests is important to ensure that your package
9+
is working as expected. It's good practice to consider that tests will run on your computer and your users' computers that may be running a different Python version and operating systems. Think about the following when running your tests:
10+
11+
1. Run your test suite in a matrix of environments that represent the Python versions and operating systems your users are likely to have.
12+
2. Running your tests in an isolated environment provides confidence in the tests and their reproducibility. This ensures that tests do not pass randomly due to your computer's specific setup. For instance, you might have unexpectedly installed dependencies on your local system that are not declared in your package's dependency list. This oversight could lead to issues when others try to install or run your package on their computers.
13+
14+
On this page, you will learn about the tools that you can use to both run tests in isolated environments and across
15+
Python versions.
16+
17+
18+
19+
### Tools to run your tests
20+
21+
There are three categories of tools that will make is easier to setup
22+
and run your tests in various environments:
23+
24+
1. A **test framework**, is a package that provides a particular syntax and set of tools for _both writing and running your tests_. Some test frameworks also have plugins that add additional features such as evaluating how much of your code the tests cover. Below you will learn about the **pytest** framework which is one of the most commonly used Python testing frameworks in the scientific ecosystem. Testing frameworks are essential but they only serve to run your tests. These frameworks don't provide a way to easily run tests across Python versions without the aid of additional automation tools.
25+
2. **Automation tools** allow you to automate running workflows such as tests in specific ways using user-defined commands. For instance it's useful to be able to run tests across different Python versions with a single command. Tools such as [**nox**](https://nox.thea.codes/en/stable/index.html) and [**tox**](https://tox.wiki/en/latest/index.html) also allow you to run tests across Python versions. However, it will be difficult to test your build on different operating systems using only nox and tox - this is where continuous integration (CI) comes into play.
26+
3. **Continuous Integration (CI):** is the last tool that you'll need to run your tests. CI will not only allow you to replicate any automated builds you create using nox or tox to run your package in different Python environments. It will also allow you to run your tests on different operating systems (Windows, Mac and Linux). [We discuss using CI to run tests here](tests-ci).
27+
28+
:::{list-table} Table: Testing & Automation Tool
29+
:widths: 40 15 15 15 15
30+
:header-rows: 1
31+
:align: center
32+
:stub-columns: 1
33+
:class: pyos-table
34+
35+
* - Features
36+
- Testing Framework (pytest)
37+
- Test Runner (Tox)
38+
- Automation Tools (Nox)
39+
- Continuous Integration (GitHub Actions)
40+
* - Run Tests Locally
41+
- <i class="fa-solid fa-circle-check fa-xl"></i>
42+
- <i class="fa-solid fa-circle-check fa-xl"></i>
43+
- <i class="fa-solid fa-circle-check fa-xl"></i>
44+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
45+
* - Run Tests Online
46+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
47+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
48+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
49+
- <i class="fa-solid fa-circle-check fa-xl"></i>
50+
* - Run Tests Across Python Versions
51+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
52+
- <i class="fa-solid fa-circle-check fa-xl"></i>
53+
- <i class="fa-solid fa-circle-check fa-xl"></i>
54+
- <i class="fa-solid fa-circle-check fa-xl"></i>
55+
* - Run Tests In Isolated Environments
56+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
57+
- <i class="fa-solid fa-circle-check fa-xl"></i>
58+
- <i class="fa-solid fa-circle-check fa-xl"></i>
59+
- <i class="fa-solid fa-circle-check fa-xl"></i>
60+
* - Run Tests Across Operating Systems (Windows, MacOS, Linux)
61+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
62+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
63+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
64+
- <i class="fa-solid fa-circle-check fa-xl"></i>
65+
* - Use for other automation tasks (e.g. building docs)
66+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
67+
- <i class="fa-solid fa-xmark fa-xl" style="color: #afb3bb;"></i>
68+
- <i class="fa-solid fa-circle-check fa-xl"></i>
69+
- <i class="fa-solid fa-circle-check fa-xl"></i>
70+
:::
71+
72+
73+
## What testing framework / package should I use to run tests?
74+
75+
We recommend using `Pytest` to build and run your package tests. Pytest is the most common testing tool used in the Python ecosystem.
76+
77+
[The Pytest package](https://docs.pytest.org/en/latest/) also has a number of
78+
extensions that can be used to add functionality such as:
79+
80+
- [pytest-cov](https://pytest-cov.readthedocs.io/en/latest/) allows you to analyze the code coverage of your package during your tests, and generates a report that you can [upload to codecov](https://codecov.io/).
81+
82+
:::{todo}
83+
[Learn more about code coverage here.](code-cov)
84+
:::
85+
86+
```{note}
87+
Your editor or IDE may add additional convenience for running tests, setting breakpoints, and toggling the `–no-cov` flag. Check your editor's documentation for more information.
88+
```
89+
90+
## Run tests using pytest
91+
92+
If you are using **pytest**, you can run your tests locally by
93+
calling:
94+
95+
`pytest`
96+
97+
Or if you want to run a specific test file - let's call this file "`test_module.py`" - you can run:
98+
99+
`pytest test_module.py`
100+
101+
Learn more from the [get started docs](https://docs.pytest.org/en/7.1.x/getting-started.html).
102+
103+
Running pytest on your computer is going to run your tests in whatever
104+
Python environment you currently have activated. This means that tests will be
105+
run on a single version of Python and only on the operating system that you
106+
are running locally.
107+
108+
An automation tool can simplify the process of running tests
109+
in various Python environments.
110+
111+
:::{admonition} Tests across operating systems
112+
If you want to run your tests across different operating systems you can [continuous integration. Learn more here](tests-ci).
113+
:::
114+
115+
### Tools to automate running your tests
116+
117+
To run tests on various Python versions or in various specific environments with a single command, you can use an automation tool such as `nox` or `tox`.
118+
Both `nox` and `tox` can create an isolated virtual environments. This allows you to easily run your tests in multiple environments and across Python versions.
119+
120+
We will focus on [Nox](https://nox.thea.codes/) in this guide. `nox` is a Python-based automation tool that builds upon the features of both `make` and `tox`. `nox` is designed to simplify and streamline testing and development workflows. Everything that you do with `nox` can be implemented using a Python-based interface.
121+
122+
```{admonition} Other automation tools you'll see in the wild
123+
:class: note
124+
125+
- **[Tox](https://tox.wiki/en/latest/index.html#useful-links)** is an automation tool that supports common steps such as building documentation, running tests across various versions of Python, and more. You can find [a nice overview of tox in the plasmaPy documentation](https://docs.plasmapy.org/en/stable/contributing/testing_guide.html#using-tox).
126+
127+
- **[Hatch](https://github.com/ofek/hatch)** is a modern end-to-end packaging tool that works with the popular build backend called hatchling. `hatch` offers a `tox`-like setup where you can run tests locally using different Python versions. If you are using `hatch` to support your packaging workflow, you may want to also use its testing capabilities rather than using `nox`.
128+
129+
* [**make:**](https://www.gnu.org/software/make/manual/make.html) Some developers use Make, which is a build automation tool, for running tests
130+
due to its versatility; it's not tied to a specific language and can be used
131+
to run various build processes. However, Make's unique syntax and approach can
132+
make it more challenging to learn, particularly if you're not already familiar
133+
with it. Make also won't manage environments for you like **nox** will do.
134+
```
135+
136+
## Run tests across Python versions with nox
137+
138+
**Nox** is a great automation tool to learn because it:
139+
140+
- Is Python-based making it accessible if you already know Python and
141+
- Will create isolated environments to run workflows.
142+
143+
`nox` simplifies creating and managing testing environments. With `nox`, you can
144+
set up virtual environments, and run tests across Python versions using the environment manager of your choice with a
145+
single command.
146+
147+
:::{note} Nox Installations
148+
149+
When you install and use nox to run tests across different Python versions, nox will create and manage individual `venv` environments for each Python version that you specify in the nox function.
150+
151+
Nox will manage each environment on its own.
152+
:::
153+
154+
Nox can also be used for other development tasks such as building
155+
documentation, creating your package distribution, and testing installations
156+
across both PyPI related environments (e.g. venv, virtualenv) and `conda` (e.g. `conda-forge`).
157+
158+
To get started with nox, you create a `noxfile.py` file at the root of your
159+
project directory. You then define commands using Python functions.
160+
Some examples of that are below.
161+
162+
## Test Environments
163+
164+
By default, `nox` uses the Python built in `venv` environment manager. A virtual environment (`venv`) is a self-contained Python environment that allows you to isolate and manage dependencies for different Python projects. It helps ensure that project-specific libraries and packages do not interfere with each other, promoting a clean and organized development environment.
165+
166+
An example of using nox to run tests in `venv` environments for Python versions 3.9, 3.10, 3.11 and 3.12 is below.
167+
168+
```{warning}
169+
Note that for the code below to work, you need to have all 4 versions of Python installed on your computer for `nox` to find.
170+
```
171+
172+
### Nox with venv environments
173+
174+
```{todo}
175+
TODO: add some tests above and show what the output would look like in the examples below...
176+
```
177+
178+
Below is an example of setting up nox to run tests using `venv` which is the built in environment manager that comes with base Python.
179+
180+
Note that the example below assumes that you have [setup your `pyproject.toml` to declare test dependencies in a way that pip
181+
can understand](../package-structure-code/declare-dependencies.md). An example
182+
of that setup is below.
183+
184+
```toml
185+
[build-system]
186+
requires = ["hatchling"]
187+
build-backend = "hatchling.build"
188+
189+
[project]
190+
name = "pyosPackage"
191+
version = "0.1.0"
192+
dependencies = [
193+
"geopandas",
194+
"xarray",
195+
]
196+
197+
[project.optional-dependencies]
198+
tests = ["pytest", "pytest-cov"]
199+
```
200+
201+
If you have the above setup, then you can use `session.install(".[tests]")` to install your test dependencies.
202+
Notice that below one single nox session allows you to run
203+
your tests on 4 different Python environments (Python 3.9, 3.10, 3.11, and 3.12).
204+
205+
```python
206+
# This code would live in a noxfile.py file located at the root of your project directory
207+
import nox
208+
209+
# For this to run you will need to have python3.9, python3.10 and python3.11 installed on your computer. Otherwise nox will skip running tests for whatever versions are missing
210+
211+
@nox.session(python=["3.9", "3.10", "3.11", "3.12"])
212+
def test(session):
213+
214+
# install
215+
session.install(".[tests]")
216+
217+
# Run tests
218+
session.run("pytest")
219+
220+
```
221+
222+
Above you create a nox session in the form of a function
223+
with a `@nox.session` decorator. Notice that within the decorator you declare the versions of python that you
224+
wish to run.
225+
226+
To run the above you'd execute the following command, specifying which session
227+
with `--session` (sometimes shortened to `-s`). Your function above
228+
is called test, therefore the session name is test.
229+
230+
```
231+
nox --session test
232+
```
233+
234+
### Nox with conda / mamba
235+
236+
Below is an example for setting up nox to use mamba (or conda) for your
237+
environment manager.
238+
Note that unlike venv, conda can automatically install
239+
the various versions of Python that you need. You won't need to install all four Python versions if you use conda/mamba, like you do with `venv`.
240+
241+
```{note}
242+
For `conda` to work with `nox`, you will need to
243+
ensure that either `conda` or `mamba` is installed on your computer.
244+
```
245+
246+
```python
247+
# This code should live in your noxfile.py file
248+
import nox
249+
250+
# The syntax below allows you to use mamba / conda as your environment manager, if you use this approach you don’t have to worry about installing different versions of Python
251+
252+
@nox.session(venv_backend='mamba', python=["3.9", "3.10", "3.11", "3.12"])
253+
def test_mamba(session):
254+
"""Nox function that installs dev requirements and runs
255+
tests on Python 3.9 through 3.12
256+
"""
257+
258+
# Install dev requirements
259+
session.conda_install(".[tests]")
260+
# Run tests using any parameters that you need
261+
session.run("pytest")
262+
```
263+
264+
To run the above session you'd use:
265+
266+
```bash
267+
nox --session test_mamba
268+
```

0 commit comments

Comments
 (0)