Skip to content

Commit 27c31c0

Browse files
committed
docs: update README
1 parent 01dfc17 commit 27c31c0

1 file changed

Lines changed: 43 additions & 35 deletions

File tree

README.md

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ This repository is intended to be a base template, a cookiecutter for a new Pyth
99
[Features](#features)
1010
 [Typing](#typing)
1111
 [Quality assurance](#quality-assurance)
12-
 [Unit testing](#unit-testing)
12+
 [Extensive testing](#extensive-testing)
1313
 [Documentation](#documentation)
1414
 [Versioning and publishing](#versioning-and-publishing)
1515
 [Dependency analysis](#dependency-analysis)
@@ -38,9 +38,9 @@ The package requires a minimum of [Python 3.10](https://www.python.org/downloads
3838

3939
A number of git hooks are invoked before and after a commit, and before push. These hooks are all managed by the [pre-commit](https://pre-commit.com/) tool and enforce a number of [software quality assurance](https://en.wikipedia.org/wiki/Software_quality_assurance) measures (see [below](#git-hooks)).
4040

41-
### Unit testing
41+
### Extensive testing
4242

43-
Comprehensive unit testing is enabled using [pytest](https://pytest.org/) combined with [doctest](https://docs.python.org/3/library/doctest.html) and [Hypothesis](https://hypothesis.works/) (to support [property-based testing](https://en.wikipedia.org/wiki/Software_testing#Property_testing)), and both code and branch coverage are measured using [coverage](https://github.com/nedbat/coveragepy) (see [below](#testing)).
43+
Comprehensive testing is enabled using [pytest](https://pytest.org/) as a test runner, combined with [doctest](https://docs.python.org/3/library/doctest.html), [Hypothesis](https://hypothesis.works/) (to support [property-based testing](https://en.wikipedia.org/wiki/Software_testing#Property_testing)), [Faker](https://github.com/joke2k/faker) and [Cases](https://github.com/smarie/python-pytest-cases) (to produce valid, localized test case data), as well as both code and branch coverage are measured using [coverage](https://github.com/nedbat/coveragepy) (see [below](#testing)).
4444

4545
### Documentation
4646

@@ -80,7 +80,7 @@ If you’d like to start your own Python project from scratch, you can either co
8080

8181
- Change the `LICENSE.md` file and the license badge according to your needs, and adjust the `SECURITY.md` file to your needs (more details [here](https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository)). Remove all content from the `CHANGELOG.md` file.
8282

83-
- Rename the `src/package/` folder to whatever your own package’s name will be, adjust the Github Actions in `.github/workflows/`, and review the `Makefile`, `pyproject.toml`, `.pre-commit-config.yaml` files as well as the unit tests accordingly. **Note**: by default all Actions run on three different host types (Linux, MacOS, and Windows) whose [rates vary widely](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#minute-multipliers), so make sure that you disable or budget accordingly if you’re in a private repository!
83+
- Rename the `src/package/` folder to whatever your own package’s name will be, adjust the Github Actions in `.github/workflows/`, and review the `Makefile`, `pyproject.toml`, `.pre-commit-config.yaml` files as well as the tests accordingly. **Note**: by default all Actions run on three different host types (Linux, MacOS, and Windows) whose [rates vary widely](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#minute-multipliers), so make sure that you disable or budget accordingly if you’re in a private repository!
8484

8585
- A new protected `release` branch, should be created if it doesn't already exist. This branch should be configured with appropriate security policies and essential checks to ensure the integrity and stability of the release process.
8686

@@ -144,7 +144,7 @@ Using the pre-commit tool and its `.pre-commit-config.yaml` configuration, the f
144144

145145
- When committing code, a number of [pre-commit hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_committing_workflow_hooks) ensure that your code is formatted according to [PEP 8](https://www.python.org/dev/peps/pep-0008/) using the [`black`](https://github.com/psf/black) tool, and they’ll invoke [`flake8`](https://github.com/PyCQA/flake8) (and various plugins), [`pylint`](https://github.com/PyCQA/pylint) and [`mypy`](https://github.com/python/mypy) to check for lint and correct types. There are more checks, but those two are the important ones. You can adjust the settings for these tools in the `pyproject.toml` or `.flake8` configuration files.
146146
- The [commit message hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_committing_workflow_hooks) enforces [conventional commit messages](https://www.conventionalcommits.org/) and that, in turn, enables a _semantic release_ of this package on the Github side: upon merging changes into the `release` branch, the [release action](https://github.com/jenstroeger/python-package-template/blob/main/.github/workflows/release.yaml) uses the [Commitizen tool](https://commitizen-tools.github.io/commitizen/) to produce a [changelog](https://en.wikipedia.org/wiki/Changelog) and it computes the next version of this package and publishes a release — all based on the commit messages of a release.
147-
- Using a [pre-push hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_other_client_hooks) this package is also set up to run [`pytest`](https://github.com/pytest-dev/pytest); in addition, the [`coverage`](https://github.com/nedbat/coveragepy) plugin makes sure that _all_ of your package’s code is covered by tests and [Hypothesis](https://hypothesis.works/) is already installed to help with generating test payloads.
147+
- Using a [pre-push hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_other_client_hooks) this package is also set up to run [`pytest`](https://github.com/pytest-dev/pytest); in addition, the [`coverage`](https://github.com/nedbat/coveragepy) plugin makes sure that _all_ of your package’s code is covered by unit tests and [Hypothesis](https://hypothesis.works/) and [Faker](https://github.com/joke2k/faker) are already installed to help with generating test case payloads.
148148
- The [`actionlint`](https://github.com/Mateusz-Grzelinski/actionlint-py) hook is set up to lint GitHub Actions workflows. If [`shellcheck`](https://github.com/koalaman/shellcheck) is installed on the system, `actionlint` runs `shellcheck` to lint the `run` steps in GitHub Actions. Note that `shellcheck` is available on [Ubuntu GitHub Actions runners](https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md) by default.
149149

150150
You can also run these hooks manually, which comes in very handy during daily development tasks. For example
@@ -163,66 +163,74 @@ runs _all_ installed git hooks over your code. For more control over the code ch
163163

164164
## Testing
165165

166-
As mentioned above, this repository is set up to use [pytest](https://pytest.org/) either standalone or as a pre-push git hook. Tests are stored in the `tests/` folder, and you can run them manually like so:
166+
As mentioned above, this repository is set up to use [pytest](https://pytest.org/) as a test runner, either standalone or as a pre-push git hook. Tests are stored in the `tests/` folder, they’re organized into unit tests, integration tests, and performance tests. You can run the tests manually like so:
167167
```bash
168-
make test
168+
make test-all # Run all tests: unit, integration, performance.
169169
```
170-
which runs all tests in both your local Python virtual environment. For more options, see the [pytest command-line flags](https://docs.pytest.org/en/7.4.x/reference/reference.html#command-line-flags). Also note that pytest includes [doctest](https://docs.python.org/3/library/doctest.html), which means that module and function [docstrings](https://www.python.org/dev/peps/pep-0257/#what-is-a-docstring), as well as the documentation, may contain test code that executes as part of the unit tests.
170+
which runs all tests in your local Python virtual environment. For more options, see the [pytest command-line flags](https://docs.pytest.org/en/7.4.x/reference/reference.html#command-line-flags).
171171

172-
Both statement and branch coverage are being tracked using [coverage](https://github.com/nedbat/coveragepy) and the [pytest-cov](https://github.com/pytest-dev/pytest-cov) plugin for pytest, and it measures how much code in the `src/package/` folder is covered by tests:
173-
```
174-
Run unit tests...........................................................Passed
175-
- hook id: pytest
176-
- duration: 0.76s
172+
There are three kinds of tests:
173+
174+
1. [Unit tests](https://en.wikipedia.org/wiki/Unit_testing) are invoked with `make test` or `make test-unit`;
175+
2. [Integration tests](https://en.wikipedia.org/wiki/Integration_testing) are invoked with `make test-integration`; and
176+
3. [Performance tests](https://en.wikipedia.org/wiki/Software_performance_testing) (using the [pytest-benchmark](https://github.com/ionelmc/pytest-benchmark) plugin) are invoked with `make test-performance`.
177+
178+
Note that the unit tests include [doctest](https://docs.python.org/3/library/doctest.html), which means that module and function [docstrings](https://www.python.org/dev/peps/pep-0257/#what-is-a-docstring), as well as the documentation, may contain test code that executes as part of the unit tests. When pushing changes to the remote, the pre-push hook runs *only* unit tests whereas *all* three kinds of tests run as part of Github’s CI.
177179

178-
============================= test session starts ==============================
179-
platform darwin -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0 -- /path/to/python-package-template/.venv/bin/python
180+
Both statement and branch coverage are being tracked using [coverage](https://github.com/nedbat/coveragepy) and the [pytest-cov](https://github.com/pytest-dev/pytest-cov) plugin for pytest when running unit tests, and it measures how much code in the `src/package/` folder is covered by tests:
181+
```
182+
=========================================== test session starts ===========================================
183+
platform darwin -- Python 3.13.9, pytest-8.4.2, pluggy-1.6.0 -- /path/to/python-package-template/.venv/bin/python
180184
cachedir: .pytest_cache
181-
hypothesis profile 'default-with-verbose-verbosity' -> max_examples=500, verbosity=Verbosity.verbose, database=DirectoryBasedExampleDatabase(PosixPath('/path/to/python-package-template/.hypothesis/examples'))
185+
hypothesis profile 'default-with-verbose-verbosity' -> verbosity=Verbosity.verbose
186+
benchmark: 5.2.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
182187
rootdir: /path/to/python-package-template
183188
configfile: pyproject.toml
184-
plugins: cov-6.0.0, hypothesis-6.122.7, env-1.1.5, custom-exit-code-0.3.0, doctestplus-1.3.0
185-
collected 3 items
189+
plugins: cases-3.9.1, hypothesis-6.138.16, env-1.1.5, cov-6.3.0, custom-exit-code-0.3.0, doctestplus-1.4.0, Faker-37.6.0, benchmark-5.2.0
190+
collected 6 items / 2 deselected / 4 selected
191+
192+
src/package/something.py::package.something.Something.do_something PASSED [ 25%]
193+
tests/unit/test_something.py::test_something_hypothesis PASSED [ 50%]
194+
tests/unit/test_something.py::test_something_cases[_case_boolean] PASSED [ 75%]
195+
docs/source/index.rst::index.rst PASSED [100%]
186196
187-
src/package/something.py::package.something.Something.do_something PASSED [ 33%]
188-
tests/test_something.py::test_something PASSED [ 66%]
189-
docs/source/index.rst::index.rst PASSED [100%]
197+
============================================= tests coverage ==============================================
198+
____________________________ coverage: platform darwin, python 3.13.9-final-0 _____________________________
190199
191-
---------- coverage: platform darwin, python 3.13.1-final-0 ----------
192200
Name Stmts Miss Branch BrPart Cover Missing
193201
----------------------------------------------------------------------
194202
src/package/__init__.py 1 0 0 0 100%
195203
src/package/something.py 4 0 0 0 100%
196204
----------------------------------------------------------------------
197205
TOTAL 5 0 0 0 100%
198-
199206
Required test coverage of 100.0% reached. Total coverage: 100.00%
200-
============================ Hypothesis Statistics =============================
201-
202-
tests/test_something.py::test_something:
207+
========================================== Hypothesis Statistics ==========================================
208+
tests/unit/test_something.py::test_something_hypothesis:
203209
204210
- during generate phase (0.00 seconds):
205211
- Typical runtimes: ~ 0-1 ms, of which < 1ms in data generation
206212
- 2 passing examples, 0 failing examples, 0 invalid examples
207213
208214
- Stopped because nothing left to do
209215
210-
211-
============================== slowest durations ===============================
212-
0.01s call tests/test_something.py::test_something
216+
============================================ slowest durations ============================================
217+
0.10s setup src/package/something.py::package.something.Something.do_something
218+
0.01s call tests/unit/test_something.py::test_something_hypothesis
213219
0.00s call src/package/something.py::package.something.Something.do_something
214-
0.00s setup src/package/something.py::package.something.Something.do_something
220+
0.00s setup tests/unit/test_something.py::test_something_cases[_case_boolean]
215221
0.00s call docs/source/index.rst::index.rst
216-
0.00s teardown src/package/something.py::package.something.Something.do_something
217222
0.00s setup docs/source/index.rst::index.rst
223+
0.00s teardown src/package/something.py::package.something.Something.do_something
224+
0.00s teardown tests/unit/test_something.py::test_something_cases[_case_boolean]
225+
0.00s call tests/unit/test_something.py::test_something_cases[_case_boolean]
226+
0.00s setup tests/unit/test_something.py::test_something_hypothesis
218227
0.00s teardown docs/source/index.rst::index.rst
219-
0.00s setup tests/test_something.py::test_something
220-
0.00s teardown tests/test_something.py::test_something
221-
============================== 3 passed in 0.09s ===============================
228+
0.00s teardown tests/unit/test_something.py::test_something_hypothesis
229+
===================================== 4 passed, 2 deselected in 0.23s =====================================
222230
```
223231
Note that code that’s not covered by tests is listed under the `Missing` column, and branches not taken too. The net effect of enforcing 100% code and branch coverage is that every new major and minor feature, every code change, and every fix are being tested (keeping in mind that high _coverage_ does not imply comprehensive, meaningful _test data_).
224232

225-
Hypothesis is a package that implements [property based testing](https://en.wikipedia.org/wiki/Software_testing#Property_testing) and that provides payload generation for your tests based on strategy descriptions ([more](https://hypothesis.works/#what-is-hypothesis)). Using its [pytest plugin](https://hypothesis.readthedocs.io/en/latest/details.html#the-hypothesis-pytest-plugin) Hypothesis is ready to be used for this package.
233+
Hypothesis is a package that implements [property based testing](https://en.wikipedia.org/wiki/Software_testing#Property_testing) and that provides payload generation for your tests based on strategy descriptions ([more](https://hypothesis.works/#what-is-hypothesis)). Using its [pytest plugin](https://hypothesis.readthedocs.io/en/latest/details.html#the-hypothesis-pytest-plugin) Hypothesis is ready to be used for this package. Likewise, the [Faker](https://github.com/joke2k/faker) package and its [pytest plugin](https://faker.readthedocs.io/en/master/#pytest-fixtures) are installed to provide valid, localized test case data (see also the [pytest-cases](https://github.com/smarie/python-pytest-cases) plugin for more details on how to separate tests and test cases).
226234

227235
## Generating documentation
228236

0 commit comments

Comments
 (0)