Compare commits
72 Commits
7.0.0.dev0
...
6.2.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1569fac603 | ||
|
|
a3599cacb5 | ||
|
|
27613b8d70 | ||
|
|
cef74be094 | ||
|
|
83dc953669 | ||
|
|
fb38e8d097 | ||
|
|
d74baf4a52 | ||
|
|
d9b8f7cf0a | ||
|
|
69212d15fa | ||
|
|
44d3282bb7 | ||
|
|
fafe00aaee | ||
|
|
477225c18a | ||
|
|
4e51b9200f | ||
|
|
b0fb02297e | ||
|
|
e47a352c49 | ||
|
|
767b3b2cc0 | ||
|
|
4eae23a633 | ||
|
|
6989435490 | ||
|
|
b178175e95 | ||
|
|
de7c19a373 | ||
|
|
82611bdc1e | ||
|
|
f0e12d4d61 | ||
|
|
3293758545 | ||
|
|
4c41b7e88b | ||
|
|
74495a2b7f | ||
|
|
a5e67a26b0 | ||
|
|
8e0b08d5da | ||
|
|
5ad0d1acb9 | ||
|
|
89b6b2ee2b | ||
|
|
ddf7d88a51 | ||
|
|
733f8027d2 | ||
|
|
8317542c9e | ||
|
|
48f78f9ba0 | ||
|
|
1e1955dbb7 | ||
|
|
ca68875eab | ||
|
|
15a45388fa | ||
|
|
017dd1ccd6 | ||
|
|
18569f44c1 | ||
|
|
d8d6812bdf | ||
|
|
a5061484d4 | ||
|
|
69ea076d55 | ||
|
|
40cb2f5b54 | ||
|
|
724e22cb00 | ||
|
|
3a2fd96305 | ||
|
|
138b19a930 | ||
|
|
822686e880 | ||
|
|
9dc54f79b0 | ||
|
|
93dbae24e1 | ||
|
|
02fdbe2e76 | ||
|
|
12e7db85af | ||
|
|
56e4392444 | ||
|
|
8220eca963 | ||
|
|
b9c98762f5 | ||
|
|
8003fd23b9 | ||
|
|
8d605b9b26 | ||
|
|
14e0c3e105 | ||
|
|
45facc16c8 | ||
|
|
99fe887d7c | ||
|
|
8dbf9dc1aa | ||
|
|
baaee2148d | ||
|
|
f7d1ab870f | ||
|
|
b8201c280e | ||
|
|
1f0c50b475 | ||
|
|
da82e1853c | ||
|
|
a566eb9c70 | ||
|
|
d3971c30f4 | ||
|
|
780044b64a | ||
|
|
8354995abc | ||
|
|
8b8b1214f4 | ||
|
|
f854cf66f4 | ||
|
|
c475106f12 | ||
|
|
e7073afe6e |
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -13,7 +13,7 @@ If this change fixes an issue, please:
|
||||
|
||||
Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:
|
||||
|
||||
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/main/changelog/README.rst) for details.
|
||||
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/master/changelog/README.rst) for details.
|
||||
|
||||
Write sentences in the **past or present tense**, examples:
|
||||
|
||||
|
||||
22
.github/workflows/main.yml
vendored
22
.github/workflows/main.yml
vendored
@@ -14,9 +14,6 @@ on:
|
||||
- main
|
||||
- "[0-9]+.[0-9]+.x"
|
||||
|
||||
env:
|
||||
PYTEST_ADDOPTS: "--color=yes"
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
@@ -112,7 +109,7 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
tox_env: "py310-xdist"
|
||||
- name: "ubuntu-pypy3"
|
||||
python: "pypy-3.7"
|
||||
python: "pypy3"
|
||||
os: ubuntu-latest
|
||||
tox_env: "pypy3-xdist"
|
||||
|
||||
@@ -163,13 +160,22 @@ jobs:
|
||||
|
||||
- name: Test with coverage
|
||||
if: "matrix.use_coverage"
|
||||
run: "tox -e ${{ matrix.tox_env }}-coverage"
|
||||
env:
|
||||
_PYTEST_TOX_COVERAGE_RUN: "coverage run -m"
|
||||
COVERAGE_PROCESS_START: ".coveragerc"
|
||||
_PYTEST_TOX_EXTRA_DEP: "coverage-enable-subprocess"
|
||||
run: "tox -e ${{ matrix.tox_env }}"
|
||||
|
||||
- name: Upload coverage
|
||||
if: matrix.use_coverage && github.repository == 'pytest-dev/pytest'
|
||||
- name: Prepare coverage token
|
||||
if: (matrix.use_coverage && ( github.repository == 'pytest-dev/pytest' || github.event_name == 'pull_request' ))
|
||||
run: |
|
||||
python scripts/append_codecov_token.py
|
||||
|
||||
- name: Report coverage
|
||||
if: (matrix.use_coverage)
|
||||
env:
|
||||
CODECOV_NAME: ${{ matrix.name }}
|
||||
run: bash scripts/upload-coverage.sh -F GHA,${{ runner.os }}
|
||||
run: bash scripts/report-coverage.sh -F GHA,${{ runner.os }}
|
||||
|
||||
linting:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
53
.github/workflows/prepare-release-pr.yml
vendored
53
.github/workflows/prepare-release-pr.yml
vendored
@@ -1,53 +0,0 @@
|
||||
name: prepare release pr
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: 'Branch to base the release from'
|
||||
required: true
|
||||
default: ''
|
||||
major:
|
||||
description: 'Major release? (yes/no)'
|
||||
required: true
|
||||
default: 'no'
|
||||
prerelease:
|
||||
description: 'Prerelease (ex: rc1). Leave empty if not a pre-release.'
|
||||
required: true
|
||||
default: ''
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.8"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade setuptools tox
|
||||
|
||||
- name: Prepare release PR (minor/patch release)
|
||||
if: github.event.inputs.major == 'no'
|
||||
run: |
|
||||
tox -e prepare-release-pr -- ${{ github.event.inputs.branch }} ${{ github.token }} --prerelease '${{ github.event.inputs.prerelease }}'
|
||||
|
||||
- name: Prepare release PR (major release)
|
||||
if: github.event.inputs.major == 'yes'
|
||||
run: |
|
||||
tox -e prepare-release-pr -- ${{ github.event.inputs.branch }} ${{ github.token }} --major --prerelease '${{ github.event.inputs.prerelease }}'
|
||||
40
.github/workflows/release-on-comment.yml
vendored
Normal file
40
.github/workflows/release-on-comment.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# part of our release process, see `release-on-comment.py`
|
||||
name: release on comment
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
|
||||
if: (github.event.comment && startsWith(github.event.comment.body, '@pytestbot please')) || (github.event.issue && !github.event.comment && startsWith(github.event.issue.body, '@pytestbot please'))
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.8"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade setuptools tox
|
||||
|
||||
- name: Prepare release
|
||||
run: |
|
||||
tox -e release-on-comment -- $GITHUB_EVENT_PATH ${{ github.token }}
|
||||
48
.github/workflows/update-plugin-list.yml
vendored
48
.github/workflows/update-plugin-list.yml
vendored
@@ -1,48 +0,0 @@
|
||||
name: Update Plugin List
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# At 00:00 on Sunday.
|
||||
# https://crontab.guru
|
||||
- cron: '0 0 * * 0'
|
||||
workflow_dispatch:
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
createPullRequest:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install packaging requests tabulate[widechars]
|
||||
|
||||
- name: Update Plugin List
|
||||
run: python scripts/update-plugin-list.py
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@2455e1596942c2902952003bbb574afbbe2ab2e6
|
||||
with:
|
||||
commit-message: '[automated] Update plugin list'
|
||||
author: 'pytest bot <pytestbot@users.noreply.github.com>'
|
||||
branch: update-plugin-list/patch
|
||||
delete-branch: true
|
||||
branch-suffix: short-commit-hash
|
||||
title: '[automated] Update plugin list'
|
||||
body: '[automated] Update plugin list'
|
||||
@@ -1,16 +1,16 @@
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 21.6b0
|
||||
rev: 19.10b0
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v1.10.0
|
||||
rev: v1.8.0
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies: [black==20.8b1]
|
||||
additional_dependencies: [black==19.10b0]
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
@@ -20,8 +20,8 @@ repos:
|
||||
- id: debug-statements
|
||||
exclude: _pytest/(debugging|hookspec).py
|
||||
language_version: python3
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 3.9.2
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.8.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
language_version: python3
|
||||
@@ -29,12 +29,12 @@ repos:
|
||||
- flake8-typing-imports==1.9.0
|
||||
- flake8-docstrings==1.5.0
|
||||
- repo: https://github.com/asottile/reorder_python_imports
|
||||
rev: v2.5.0
|
||||
rev: v2.3.5
|
||||
hooks:
|
||||
- id: reorder-python-imports
|
||||
args: ['--application-directories=.:src', --py36-plus]
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.19.4
|
||||
rev: v2.7.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py36-plus]
|
||||
@@ -44,11 +44,11 @@ repos:
|
||||
- id: setup-cfg-fmt
|
||||
args: [--max-py-version=3.10]
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.9.0
|
||||
rev: v1.6.0
|
||||
hooks:
|
||||
- id: python-use-type-annotations
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.902
|
||||
rev: v0.790
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: ^(src/|testing/)
|
||||
@@ -58,8 +58,6 @@ repos:
|
||||
- py>=1.8.2
|
||||
- attrs>=19.2.0
|
||||
- packaging
|
||||
- types-toml
|
||||
- types-pkg_resources
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: rst
|
||||
@@ -90,9 +88,3 @@ repos:
|
||||
xml\.
|
||||
)
|
||||
types: [python]
|
||||
- id: py-path-deprecated
|
||||
name: py.path usage is deprecated
|
||||
exclude: docs|src/_pytest/deprecated.py|testing/deprecated_test.py
|
||||
language: pygrep
|
||||
entry: \bpy\.path\.local
|
||||
types: [python]
|
||||
|
||||
13
AUTHORS
13
AUTHORS
@@ -5,7 +5,6 @@ Contributors include::
|
||||
|
||||
Aaron Coleman
|
||||
Abdeali JK
|
||||
Abdelrahman Elbehery
|
||||
Abhijeet Kasurde
|
||||
Adam Johnson
|
||||
Adam Uhlir
|
||||
@@ -24,7 +23,6 @@ Andras Tim
|
||||
Andrea Cimatoribus
|
||||
Andreas Motl
|
||||
Andreas Zeidler
|
||||
Andrew Shapton
|
||||
Andrey Paramonov
|
||||
Andrzej Klajnert
|
||||
Andrzej Ostrowski
|
||||
@@ -32,7 +30,6 @@ Andy Freeland
|
||||
Anthon van der Neut
|
||||
Anthony Shaw
|
||||
Anthony Sottile
|
||||
Anton Grinevich
|
||||
Anton Lodder
|
||||
Antony Lee
|
||||
Arel Cordero
|
||||
@@ -43,7 +40,6 @@ Aron Curzon
|
||||
Aviral Verma
|
||||
Aviv Palivoda
|
||||
Barney Gale
|
||||
Ben Gartner
|
||||
Ben Webb
|
||||
Benjamin Peterson
|
||||
Bernard Pratz
|
||||
@@ -62,7 +58,6 @@ Charles Machalow
|
||||
Charnjit SiNGH (CCSJ)
|
||||
Chris Lamb
|
||||
Chris NeJame
|
||||
Chris Rose
|
||||
Christian Boelsen
|
||||
Christian Fetzer
|
||||
Christian Neumüller
|
||||
@@ -81,7 +76,6 @@ Daniel Grana
|
||||
Daniel Hahler
|
||||
Daniel Nuri
|
||||
Daniel Wandschneider
|
||||
Daniele Procida
|
||||
Danielle Jenkins
|
||||
Daniil Galiev
|
||||
Dave Hunt
|
||||
@@ -101,7 +95,6 @@ Dominic Mortlock
|
||||
Duncan Betts
|
||||
Edison Gustavo Muenz
|
||||
Edoardo Batini
|
||||
Edson Tadeu M. Manoel
|
||||
Eduardo Schettino
|
||||
Eli Boyarski
|
||||
Elizaveta Shashkova
|
||||
@@ -144,7 +137,6 @@ Iwan Briquemont
|
||||
Jaap Broekhuizen
|
||||
Jakob van Santen
|
||||
Jakub Mitoraj
|
||||
James Bourbeau
|
||||
Jan Balster
|
||||
Janne Vanhala
|
||||
Jason R. Coombs
|
||||
@@ -165,7 +157,6 @@ Josh Karpel
|
||||
Joshua Bronson
|
||||
Jurko Gospodnetić
|
||||
Justyna Janczyszyn
|
||||
Justice Ndou
|
||||
Kale Kundert
|
||||
Kamran Ahmad
|
||||
Karl O. Pinc
|
||||
@@ -233,7 +224,6 @@ Nicholas Murphy
|
||||
Niclas Olofsson
|
||||
Nicolas Delaby
|
||||
Nikolay Kondratyev
|
||||
Olga Matoula
|
||||
Oleg Pidsadnyi
|
||||
Oleg Sushchenko
|
||||
Oliver Bestwalter
|
||||
@@ -241,7 +231,6 @@ Omar Kohl
|
||||
Omer Hadari
|
||||
Ondřej Súkup
|
||||
Oscar Benjamin
|
||||
Parth Patel
|
||||
Patrick Hayes
|
||||
Pauli Virtanen
|
||||
Pavel Karateev
|
||||
@@ -276,7 +265,6 @@ Ross Lawley
|
||||
Ruaridh Williamson
|
||||
Russel Winder
|
||||
Ryan Wooden
|
||||
Saiprasad Kale
|
||||
Samuel Dion-Girardeau
|
||||
Samuel Searles-Bryant
|
||||
Samuele Pedroni
|
||||
@@ -337,6 +325,5 @@ Xuan Luong
|
||||
Xuecong Liao
|
||||
Yoav Caspi
|
||||
Zac Hatfield-Dodds
|
||||
Zachary Kneupper
|
||||
Zoltán Máté
|
||||
Zsolt Cserna
|
||||
|
||||
@@ -4,4 +4,4 @@ Changelog
|
||||
|
||||
The pytest CHANGELOG is located `here <https://docs.pytest.org/en/stable/changelog.html>`__.
|
||||
|
||||
The source document can be found at: https://github.com/pytest-dev/pytest/blob/main/doc/en/changelog.rst
|
||||
The source document can be found at: https://github.com/pytest-dev/pytest/blob/master/doc/en/changelog.rst
|
||||
|
||||
@@ -160,7 +160,7 @@ the following:
|
||||
|
||||
- an issue tracker for bug reports and enhancement requests.
|
||||
|
||||
- a `changelog <https://keepachangelog.com/>`_.
|
||||
- a `changelog <http://keepachangelog.com/>`_.
|
||||
|
||||
If no contributor strongly objects and two agree, the repository can then be
|
||||
transferred to the ``pytest-dev`` organisation.
|
||||
@@ -234,7 +234,7 @@ Here is a simple overview, with pytest-specific bits:
|
||||
|
||||
$ git clone git@github.com:YOUR_GITHUB_USERNAME/pytest.git
|
||||
$ cd pytest
|
||||
# now, create your own branch off "main":
|
||||
# now, create your own branch off "master":
|
||||
|
||||
$ git checkout -b your-bugfix-branch-name main
|
||||
|
||||
@@ -259,7 +259,7 @@ Here is a simple overview, with pytest-specific bits:
|
||||
|
||||
Tox is used to run all the tests and will automatically setup virtualenvs
|
||||
to run the tests in.
|
||||
(will implicitly use https://virtualenv.pypa.io/en/latest/)::
|
||||
(will implicitly use http://www.virtualenv.org/en/latest/)::
|
||||
|
||||
$ pip install tox
|
||||
|
||||
@@ -324,20 +324,20 @@ Here is a simple overview, with pytest-specific bits:
|
||||
Writing Tests
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Writing tests for plugins or for pytest itself is often done using the `pytester fixture <https://docs.pytest.org/en/stable/reference.html#pytester>`_, as a "black-box" test.
|
||||
Writing tests for plugins or for pytest itself is often done using the `testdir fixture <https://docs.pytest.org/en/stable/reference.html#testdir>`_, as a "black-box" test.
|
||||
|
||||
For example, to ensure a simple test passes you can write:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def test_true_assertion(pytester):
|
||||
pytester.makepyfile(
|
||||
def test_true_assertion(testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test_foo():
|
||||
assert True
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result = testdir.runpytest()
|
||||
result.assert_outcomes(failed=0, passed=1)
|
||||
|
||||
|
||||
@@ -346,14 +346,14 @@ Alternatively, it is possible to make checks based on the actual output of the t
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def test_true_assertion(pytester):
|
||||
pytester.makepyfile(
|
||||
def test_true_assertion(testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test_foo():
|
||||
assert False
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(["*assert False*", "*1 failed*"])
|
||||
|
||||
When choosing a file where to write a new test, take a look at the existing files and see if there's
|
||||
@@ -387,15 +387,15 @@ Suppose for example that the latest release was 1.2.3, and you want to include
|
||||
a bug fix in 1.2.4 (check https://github.com/pytest-dev/pytest/releases for the
|
||||
actual latest release). The procedure for this is:
|
||||
|
||||
#. First, make sure the bug is fixed the ``main`` branch, with a regular pull
|
||||
#. First, make sure the bug is fixed the ``master`` branch, with a regular pull
|
||||
request, as described above. An exception to this is if the bug fix is not
|
||||
applicable to ``main`` anymore.
|
||||
applicable to ``master`` anymore.
|
||||
|
||||
#. ``git checkout origin/1.2.x -b backport-XXXX`` # use the main PR number here
|
||||
#. ``git checkout origin/1.2.x -b backport-XXXX`` # use the master PR number here
|
||||
|
||||
#. Locate the merge commit on the PR, in the *merged* message, for example:
|
||||
|
||||
nicoddemus merged commit 0f8b462 into pytest-dev:main
|
||||
nicoddemus merged commit 0f8b462 into pytest-dev:master
|
||||
|
||||
#. ``git cherry-pick -x -m1 REVISION`` # use the revision you found above (``0f8b462``).
|
||||
|
||||
@@ -408,8 +408,8 @@ actual latest release). The procedure for this is:
|
||||
Who does the backporting
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As mentioned above, bugs should first be fixed on ``main`` (except in rare occasions
|
||||
that a bug only happens in a previous release). So, who should do the backport procedure described
|
||||
As mentioned above, bugs should first be fixed on ``master`` (except in rare occasions
|
||||
that a bug only happens in a previous release). So who should do the backport procedure described
|
||||
above?
|
||||
|
||||
1. If the bug was fixed by a core developer, it is the main responsibility of that core developer
|
||||
@@ -417,8 +417,8 @@ above?
|
||||
2. However, often the merge is done by another maintainer, in which case it is nice of them to
|
||||
do the backport procedure if they have the time.
|
||||
3. For bugs submitted by non-maintainers, it is expected that a core developer will to do
|
||||
the backport, normally the one that merged the PR on ``main``.
|
||||
4. If a non-maintainers notices a bug which is fixed on ``main`` but has not been backported
|
||||
the backport, normally the one that merged the PR on ``master``.
|
||||
4. If a non-maintainers notices a bug which is fixed on ``master`` but has not been backported
|
||||
(due to maintainers forgetting to apply the *needs backport* label, or just plain missing it),
|
||||
they are also welcome to open a PR with the backport. The procedure is simple and really
|
||||
helps with the maintenance of the project.
|
||||
@@ -447,7 +447,7 @@ can always reopen the issue/pull request in their own time later if it makes sen
|
||||
When to close
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Here are a few general rules the maintainers use deciding when to close issues/PRs because
|
||||
Here are a few general rules the maintainers use to decide when to close issues/PRs because
|
||||
of lack of inactivity:
|
||||
|
||||
* Issues labeled ``question`` or ``needs information``: closed after 14 days inactive.
|
||||
@@ -459,15 +459,15 @@ The above are **not hard rules**, but merely **guidelines**, and can be (and oft
|
||||
Closing pull requests
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When closing a Pull Request, it needs to be acknowledging the time, effort, and interest demonstrated by the person which submitted it. As mentioned previously, it is not the intent of the team to dismiss a stalled pull request entirely but to merely to clear up our queue, so a message like the one below is warranted when closing a pull request that went stale:
|
||||
When closing a Pull Request, it needs to be acknowledge the time, effort, and interest demonstrated by the person which submitted it. As mentioned previously, it is not the intent of the team to dismiss stalled pull request entirely but to merely to clear up our queue, so a message like the one below is warranted when closing a pull request that went stale:
|
||||
|
||||
Hi <contributor>,
|
||||
|
||||
First of all, we would like to thank you for your time and effort on working on this, the pytest team deeply appreciates it.
|
||||
First of all we would like to thank you for your time and effort on working on this, the pytest team deeply appreciates it.
|
||||
|
||||
We noticed it has been awhile since you have updated this PR, however. pytest is a high activity project, with many issues/PRs being opened daily, so it is hard for us maintainers to track which PRs are ready for merging, for review, or need more attention.
|
||||
|
||||
So for those reasons we, think it is best to close the PR for now, but with the only intention to clean up our queue, it is by no means a rejection of your changes. We still encourage you to re-open this PR (it is just a click of a button away) when you are ready to get back to it.
|
||||
So for those reasons we think it is best to close the PR for now, but with the only intention to cleanup our queue, it is by no means a rejection of your changes. We still encourage you to re-open this PR (it is just a click of a button away) when you are ready to get back to it.
|
||||
|
||||
Again we appreciate your time for working on this, and hope you might get back to this at a later time!
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2004-2021 Holger Krekel and others
|
||||
Copyright (c) 2004-2020 Holger Krekel and others
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
.. image:: https://github.com/pytest-dev/pytest/raw/main/doc/en/img/pytest_logo_curves.svg
|
||||
:target: https://docs.pytest.org/en/stable/
|
||||
:align: center
|
||||
:height: 200
|
||||
:alt: pytest
|
||||
|
||||
|
||||
@@ -20,11 +19,14 @@
|
||||
:target: https://codecov.io/gh/pytest-dev/pytest
|
||||
:alt: Code coverage Status
|
||||
|
||||
.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master
|
||||
:target: https://travis-ci.org/pytest-dev/pytest
|
||||
|
||||
.. image:: https://github.com/pytest-dev/pytest/workflows/main/badge.svg
|
||||
:target: https://github.com/pytest-dev/pytest/actions?query=workflow%3Amain
|
||||
|
||||
.. image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest/main.svg
|
||||
:target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/main
|
||||
:target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/master
|
||||
:alt: pre-commit.ci status
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
@@ -93,7 +95,7 @@ Features
|
||||
|
||||
- Python 3.6+ and PyPy3
|
||||
|
||||
- Rich plugin architecture, with over 850+ `external plugins <https://docs.pytest.org/en/latest/reference/plugin_list.html>`_ and thriving community
|
||||
- Rich plugin architecture, with over 850+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community
|
||||
|
||||
|
||||
Documentation
|
||||
|
||||
112
RELEASING.rst
112
RELEASING.rst
@@ -14,89 +14,59 @@ Preparing: Automatic Method
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We have developed an automated workflow for releases, that uses GitHub workflows and is triggered
|
||||
by `manually running <https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow>`__
|
||||
the `prepare-release-pr workflow <https://github.com/pytest-dev/pytest/actions/workflows/prepare-release-pr.yml>`__
|
||||
on GitHub Actions.
|
||||
by opening an issue.
|
||||
|
||||
The automation will decide the new version number based on the following criteria:
|
||||
Bug-fix releases
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
- If the "major release" input is set to "yes", release a new major release
|
||||
(e.g. 7.0.0 -> 8.0.0)
|
||||
- If there are any ``.feature.rst`` or ``.breaking.rst`` files in the
|
||||
``changelog`` directory, release a new minor release (e.g. 7.0.0 -> 7.1.0)
|
||||
- Otherwise, release a bugfix release (e.g. 7.0.0 -> 7.0.1)
|
||||
- If the "prerelease" input is set, append the string to the version number
|
||||
(e.g. 7.0.0 -> 8.0.0rc1), if "major" is set, and "prerelease" is set to `rc1`)
|
||||
A bug-fix release is always done from a maintenance branch, so for example to release bug-fix
|
||||
``5.1.2``, open a new issue and add this comment to the body::
|
||||
|
||||
Bug-fix and minor releases
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@pytestbot please prepare release from 5.1.x
|
||||
|
||||
Bug-fix and minor releases are always done from a maintenance branch. First,
|
||||
consider double-checking the ``changelog`` directory to see if there are any
|
||||
breaking changes or new features.
|
||||
Where ``5.1.x`` is the maintenance branch for the ``5.1`` series.
|
||||
|
||||
For a new minor release, first create a new maintenance branch from ``main``::
|
||||
The automated workflow will publish a PR for a branch ``release-5.1.2``
|
||||
and notify it as a comment in the issue.
|
||||
|
||||
git fetch --all
|
||||
git branch 7.1.x upstream/main
|
||||
git push upstream 7.1.x
|
||||
|
||||
Then, trigger the workflow with the following inputs:
|
||||
|
||||
- branch: **7.1.x**
|
||||
- major release: **no**
|
||||
- prerelease: empty
|
||||
|
||||
Or via the commandline using `GitHub's cli <https://github.com/cli/cli>`__::
|
||||
|
||||
gh workflow run prepare-release-pr.yml -f branch=7.1.x -f major=no -f prerelease=
|
||||
|
||||
Where ``7.1.x`` is the maintenance branch for the ``7.1`` series. The automated
|
||||
workflow will publish a PR for a branch ``release-7.1.0``.
|
||||
|
||||
Similarly, for a bug-fix release, use the existing maintenance branch and
|
||||
trigger the workflow with e.g. ``branch: 7.0.x`` to get a new ``release-7.0.1``
|
||||
PR.
|
||||
|
||||
Major releases
|
||||
Minor releases
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
1. Create a new maintenance branch from ``main``::
|
||||
1. Create a new maintenance branch from ``master``::
|
||||
|
||||
git fetch --all
|
||||
git branch 8.0.x upstream/main
|
||||
git push upstream 8.0.x
|
||||
git branch 5.2.x upstream/master
|
||||
git push upstream 5.2.x
|
||||
|
||||
2. Trigger the workflow with the following inputs:
|
||||
2. Open a new issue and add this comment to the body::
|
||||
|
||||
- branch: **8.0.x**
|
||||
- major release: **yes**
|
||||
- prerelease: empty
|
||||
@pytestbot please prepare release from 5.2.x
|
||||
|
||||
Or via the commandline::
|
||||
The automated workflow will publish a PR for a branch ``release-5.2.0`` and
|
||||
notify it as a comment in the issue.
|
||||
|
||||
gh workflow run prepare-release-pr.yml -f branch=8.0.x -f major=yes -f prerelease=
|
||||
Major and release candidates
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The automated workflow will publish a PR for a branch ``release-8.0.0``.
|
||||
1. Create a new maintenance branch from ``master``::
|
||||
|
||||
git fetch --all
|
||||
git branch 6.0.x upstream/master
|
||||
git push upstream 6.0.x
|
||||
|
||||
2. For a **major release**, open a new issue and add this comment in the body::
|
||||
|
||||
@pytestbot please prepare major release from 6.0.x
|
||||
|
||||
For a **release candidate**, the comment must be (TODO: `#7551 <https://github.com/pytest-dev/pytest/issues/7551>`__)::
|
||||
|
||||
@pytestbot please prepare release candidate from 6.0.x
|
||||
|
||||
The automated workflow will publish a PR for a branch ``release-6.0.0`` and
|
||||
notify it as a comment in the issue.
|
||||
|
||||
At this point on, this follows the same workflow as other maintenance branches: bug-fixes are merged
|
||||
into ``main`` and ported back to the maintenance branch, even for release candidates.
|
||||
|
||||
Release candidates
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To release a release candidate, set the "prerelease" input to the version number
|
||||
suffix to use. To release a ``8.0.0rc1``, proceed like under "major releases", but set:
|
||||
|
||||
- branch: 8.0.x
|
||||
- major release: yes
|
||||
- prerelease: **rc1**
|
||||
|
||||
Or via the commandline::
|
||||
|
||||
gh workflow run prepare-release-pr.yml -f branch=8.0.x -f major=yes -f prerelease=rc1
|
||||
|
||||
The automated workflow will publish a PR for a branch ``release-8.0.0rc1``.
|
||||
into ``master`` and ported back to the maintenance branch, even for release candidates.
|
||||
|
||||
**A note about release candidates**
|
||||
|
||||
@@ -113,7 +83,7 @@ to be executed on that platform.
|
||||
To release a version ``MAJOR.MINOR.PATCH``, follow these steps:
|
||||
|
||||
#. For major and minor releases, create a new branch ``MAJOR.MINOR.x`` from
|
||||
``upstream/main`` and push it to ``upstream``.
|
||||
``upstream/master`` and push it to ``upstream``.
|
||||
|
||||
#. Create a branch ``release-MAJOR.MINOR.PATCH`` from the ``MAJOR.MINOR.x`` branch.
|
||||
|
||||
@@ -144,18 +114,18 @@ Both automatic and manual processes described above follow the same steps from t
|
||||
|
||||
#. Merge the PR.
|
||||
|
||||
#. Cherry-pick the CHANGELOG / announce files to the ``main`` branch::
|
||||
#. Cherry-pick the CHANGELOG / announce files to the ``master`` branch::
|
||||
|
||||
git fetch --all --prune
|
||||
git checkout upstream/main -b cherry-pick-release
|
||||
git checkout origin/master -b cherry-pick-release
|
||||
git cherry-pick -x -m1 upstream/MAJOR.MINOR.x
|
||||
|
||||
#. Open a PR for ``cherry-pick-release`` and merge it once CI passes. No need to wait for approvals if there were no conflicts on the previous step.
|
||||
|
||||
#. For major and minor releases, tag the release cherry-pick merge commit in main with
|
||||
#. For major and minor releases, tag the release cherry-pick merge commit in master with
|
||||
a dev tag for the next feature release::
|
||||
|
||||
git checkout main
|
||||
git checkout master
|
||||
git pull
|
||||
git tag MAJOR.{MINOR+1}.0.dev0
|
||||
git push git@github.com:pytest-dev/pytest.git MAJOR.{MINOR+1}.0.dev0
|
||||
|
||||
@@ -25,7 +25,6 @@ The current list of contributors receiving funding are:
|
||||
|
||||
* `@asottile`_
|
||||
* `@nicoddemus`_
|
||||
* `@The-Compiler`_
|
||||
|
||||
Contributors interested in receiving a part of the funds just need to submit a PR adding their
|
||||
name to the list. Contributors that want to stop receiving the funds should also submit a PR
|
||||
@@ -57,4 +56,3 @@ funds. Just drop a line to one of the `@pytest-dev/tidelift-admins`_ or use the
|
||||
|
||||
.. _`@asottile`: https://github.com/asottile
|
||||
.. _`@nicoddemus`: https://github.com/nicoddemus
|
||||
.. _`@The-Compiler`: https://github.com/The-Compiler
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Add automatically generated :ref:`plugin-list`. The list is updated on a periodic schedule.
|
||||
@@ -1,7 +0,0 @@
|
||||
Added :meth:`cache.mkdir() <pytest.Cache.mkdir>`, which is similar to the existing :meth:`cache.makedir() <pytest.Cache.makedir>`,
|
||||
but returns a :class:`pathlib.Path` instead of a legacy ``py.path.local``.
|
||||
|
||||
Added a ``paths`` type to :meth:`parser.addini() <pytest.Parser.addini>`,
|
||||
as in ``parser.addini("mypaths", "my paths", type="paths")``,
|
||||
which is similar to the existing ``pathlist``,
|
||||
but returns a list of :class:`pathlib.Path` instead of legacy ``py.path.local``.
|
||||
@@ -1,12 +0,0 @@
|
||||
Directly constructing the following classes is now deprecated:
|
||||
|
||||
- ``_pytest.mark.structures.Mark``
|
||||
- ``_pytest.mark.structures.MarkDecorator``
|
||||
- ``_pytest.mark.structures.MarkGenerator``
|
||||
- ``_pytest.python.Metafunc``
|
||||
- ``_pytest.runner.CallInfo``
|
||||
- ``_pytest._code.ExceptionInfo``
|
||||
- ``_pytest.config.argparsing.Parser``
|
||||
- ``_pytest.config.argparsing.OptionGroup``
|
||||
|
||||
These have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 7.0.0.
|
||||
@@ -1,19 +0,0 @@
|
||||
The types of objects used in pytest's API are now exported so they may be used in type annotations.
|
||||
|
||||
The newly-exported types are:
|
||||
|
||||
- ``pytest.Config`` for :class:`Config <pytest.Config>`.
|
||||
- ``pytest.Mark`` for :class:`marks <pytest.Mark>`.
|
||||
- ``pytest.MarkDecorator`` for :class:`mark decorators <pytest.MarkDecorator>`.
|
||||
- ``pytest.MarkGenerator`` for the :class:`pytest.mark <pytest.MarkGenerator>` singleton.
|
||||
- ``pytest.Metafunc`` for the :class:`metafunc <pytest.MarkGenerator>` argument to the :func:`pytest_generate_tests <pytest.hookspec.pytest_generate_tests>` hook.
|
||||
- ``pytest.CallInfo`` for the :class:`CallInfo <pytest.CallInfo>` type passed to various hooks.
|
||||
- ``pytest.PytestPluginManager`` for :class:`PytestPluginManager <pytest.PytestPluginManager>`.
|
||||
- ``pytest.ExceptionInfo`` for the :class:`ExceptionInfo <pytest.ExceptionInfo>` type returned from :func:`pytest.raises` and passed to various hooks.
|
||||
- ``pytest.Parser`` for the :class:`Parser <pytest.Parser>` type passed to the :func:`pytest_addoption <pytest.hookspec.pytest_addoption>` hook.
|
||||
- ``pytest.OptionGroup`` for the :class:`OptionGroup <pytest.OptionGroup>` type returned from the :func:`parser.addgroup <pytest.Parser.getgroup>` method.
|
||||
|
||||
Constructing them directly is not supported; they are only meant for use in type annotations.
|
||||
Doing so will emit a deprecation warning, and may become a hard-error in pytest 7.0.
|
||||
|
||||
Subclassing them is also not supported. This is not currently enforced at runtime, but is detected by type-checkers such as mypy.
|
||||
@@ -1,2 +0,0 @@
|
||||
:ref:`--import-mode=importlib <import-modes>` now works with features that
|
||||
depend on modules being on :py:data:`sys.modules`, such as :mod:`pickle` and :mod:`dataclasses`.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed failing staticmethod test cases if they are inherited from a parent test class.
|
||||
@@ -1,7 +0,0 @@
|
||||
The following hooks now receive an additional ``pathlib.Path`` argument, equivalent to an existing ``py.path.local`` argument:
|
||||
|
||||
- :func:`pytest_ignore_collect <_pytest.hookspec.pytest_ignore_collect>` - The ``fspath`` parameter (equivalent to existing ``path`` parameter).
|
||||
- :func:`pytest_collect_file <_pytest.hookspec.pytest_collect_file>` - The ``fspath`` parameter (equivalent to existing ``path`` parameter).
|
||||
- :func:`pytest_pycollect_makemodule <_pytest.hookspec.pytest_pycollect_makemodule>` - The ``fspath`` parameter (equivalent to existing ``path`` parameter).
|
||||
- :func:`pytest_report_header <_pytest.hookspec.pytest_report_header>` - The ``startpath`` parameter (equivalent to existing ``startdir`` parameter).
|
||||
- :func:`pytest_report_collectionfinish <_pytest.hookspec.pytest_report_collectionfinish>` - The ``startpath`` parameter (equivalent to existing ``startdir`` parameter).
|
||||
@@ -1,6 +0,0 @@
|
||||
The following changes have been made to internal pytest types/functions:
|
||||
|
||||
- The ``path`` property of ``_pytest.code.Code`` returns ``Path`` instead of ``py.path.local``.
|
||||
- The ``path`` property of ``_pytest.code.TracebackEntry`` returns ``Path`` instead of ``py.path.local``.
|
||||
- The ``_pytest.code.getfslineno()`` function returns ``Path`` instead of ``py.path.local``.
|
||||
- The ``_pytest.python.path_matches_patterns()`` function takes ``Path`` instead of ``py.path.local``.
|
||||
@@ -1,3 +0,0 @@
|
||||
``testdir.makefile`` now silently accepts values which don't start with ``.`` to maintain backward compatibility with older pytest versions.
|
||||
|
||||
``pytester.makefile`` now issues a clearer error if the ``.`` is missing in the ``ext`` argument.
|
||||
@@ -1,7 +0,0 @@
|
||||
Raising :class:`unittest.SkipTest` to skip collection of tests during the
|
||||
pytest collection phase is deprecated. Use :func:`pytest.skip` instead.
|
||||
|
||||
Note: This deprecation only relates to using `unittest.SkipTest` during test
|
||||
collection. You are probably not doing that. Ordinary usage of
|
||||
:class:`unittest.SkipTest` / :meth:`unittest.TestCase.skipTest` /
|
||||
:func:`unittest.skip` in unittest test cases is fully supported.
|
||||
@@ -1 +0,0 @@
|
||||
``--version`` now writes version information to ``stdout`` rather than ``stderr``.
|
||||
@@ -1 +0,0 @@
|
||||
Internal Restructure: let python.PyObjMixing inherit from nodes.Node to carry over typing information.
|
||||
@@ -1 +0,0 @@
|
||||
Deprecate ``Node.fspath`` as we plan to move off `py.path.local <https://py.readthedocs.io/en/latest/path.html>`__ and switch to :mod:``pathlib``.
|
||||
@@ -1 +0,0 @@
|
||||
Implement ``Node.path`` as a ``pathlib.Path``.
|
||||
@@ -1,3 +0,0 @@
|
||||
Fixed issue where pytest's ``faulthandler`` support would not dump traceback on crashes
|
||||
if the :mod:`faulthandler` module was already enabled during pytest startup (using
|
||||
``python -X dev -m pytest`` for example).
|
||||
@@ -1,5 +0,0 @@
|
||||
Several behaviors of :meth:`Parser.addoption <pytest.Parser.addoption>` are now
|
||||
scheduled for removal in pytest 7 (deprecated since pytest 2.4.0):
|
||||
|
||||
- ``parser.addoption(..., help=".. %default ..")`` - use ``%(default)s`` instead.
|
||||
- ``parser.addoption(..., type="int/string/float/complex")`` - use ``type=int`` etc. instead.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed an issue where illegal directory characters derived from ``getpass.getuser()`` raised an ``OSError``.
|
||||
@@ -1,10 +0,0 @@
|
||||
Improved :func:`pytest.approx` assertion messages for sequences of numbers.
|
||||
|
||||
The assertion messages now dumps a table with the index and the error of each diff.
|
||||
Example::
|
||||
|
||||
> assert [1, 2, 3, 4] == pytest.approx([1, 3, 3, 5])
|
||||
E assert comparison failed for 2 values:
|
||||
E Index | Obtained | Expected
|
||||
E 1 | 2 | 3 +- 3.0e-06
|
||||
E 3 | 4 | 5 +- 5.0e-06
|
||||
@@ -1 +0,0 @@
|
||||
Recommend `numpy.testing <https://numpy.org/doc/stable/reference/routines.testing.html>`__ module on :func:`pytest.approx` documentation.
|
||||
@@ -1 +0,0 @@
|
||||
Fix ``Class.from_parent`` so it forwards extra keyword arguments to the constructor.
|
||||
@@ -1 +0,0 @@
|
||||
The ``@pytest.mark.skip`` decorator now correctly handles its arguments. When the ``reason`` argument is accidentally given both positional and as a keyword (e.g. because it was confused with ``skipif``), a ``TypeError`` now occurs. Before, such tests were silently skipped, and the positional argument ignored. Additionally, ``reason`` is now documented correctly as positional or keyword (rather than keyword-only).
|
||||
@@ -1 +0,0 @@
|
||||
Use private names for internal fixtures that handle classic setup/teardown so that they don't show up with the default ``--fixtures`` invocation (but they still show up with ``--fixtures -v``).
|
||||
@@ -1,5 +0,0 @@
|
||||
By default, pytest will truncate long strings in assert errors so they don't clutter the output too much,
|
||||
currently at ``240`` characters by default.
|
||||
|
||||
However, in some cases the longer output helps, or is even crucial, to diagnose a failure. Using ``-v`` will
|
||||
now increase the truncation threshold to ``2400`` characters, and ``-vv`` or higher will disable truncation entirely.
|
||||
@@ -1 +0,0 @@
|
||||
Assert the outcomes for the issue 518 test and fix the test.
|
||||
@@ -1 +0,0 @@
|
||||
:func:`pytest.approx` now works on :class:`~decimal.Decimal` within mappings/dicts and sequences/lists.
|
||||
@@ -1,4 +0,0 @@
|
||||
Defining a custom pytest node type which is both an item and a collector now issues a warning.
|
||||
It was never sanely supported and triggers hard to debug errors.
|
||||
|
||||
Instead, a separate collector node should be used, which collects the item. See :ref:`non-python tests` for an example.
|
||||
@@ -1 +0,0 @@
|
||||
The :confval:`required_plugins` config option now works correctly when pre-releases of plugins are installed, rather than falsely claiming that those plugins aren't installed at all.
|
||||
@@ -1 +0,0 @@
|
||||
``-c <config file>`` now also properly defines ``rootdir`` as the directory that contains ``<config file>``.
|
||||
@@ -1 +0,0 @@
|
||||
Python 3.10 is now supported.
|
||||
@@ -1,4 +0,0 @@
|
||||
:meth:`pytest.MonkeyPatch.syspath_prepend` no longer fails when
|
||||
``setuptools`` is not installed.
|
||||
It now only calls :func:`pkg_resources.fixup_namespace_packages` if
|
||||
``pkg_resources`` was previously imported, because it is not needed otherwise.
|
||||
@@ -1,5 +0,0 @@
|
||||
Fixed issue where `TestCase.setUpClass` is not called when a test has `/` in its name since pytest 6.2.0.
|
||||
|
||||
This refers to the path part in pytest node IDs, e.g. `TestClass::test_it` in the node ID `tests/test_file.py::TestClass::test_it`.
|
||||
|
||||
Now, instead of assuming that the test name does not contain ``/``, it is assumed that test path does not contain ``::``. We plan to hopefully make both of these work in the future.
|
||||
@@ -1 +0,0 @@
|
||||
Introduce fix to handle precision width in ``log-cli-format`` in turn to fix output coloring for certain formats.
|
||||
@@ -1,5 +0,0 @@
|
||||
pytest invocations with ``--fixtures-per-test`` and ``--fixtures`` have been enabled with:
|
||||
|
||||
- Fixture location path printed with the fixture name.
|
||||
- First section of the fixture's docstring printed under the fixture name.
|
||||
- Whole of fixture's docstring printed under the fixture name using ``--verbose`` option.
|
||||
@@ -1,4 +0,0 @@
|
||||
Reducing confusion from `pytest.warns(None)` by:
|
||||
|
||||
- Allowing no arguments to be passed in order to catch any exception (no argument defaults to `Warning`).
|
||||
- Emit a deprecation warning if passed `None`.
|
||||
@@ -1 +0,0 @@
|
||||
Help text for ``--pdbcls`` more accurately reflects the option's behavior.
|
||||
@@ -1 +0,0 @@
|
||||
New :ref:`version-tuple` attribute, which makes it simpler for users to do something depending on the pytest version (such as declaring hooks which are introduced in later versions).
|
||||
@@ -1,19 +1,12 @@
|
||||
<h3>Contents</h3>
|
||||
<h3><a href="{{ pathto(master_doc) }}">{{ _('Table Of Contents') }}</a></h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="{{ pathto('index') }}">Home</a></li>
|
||||
|
||||
<li><a href="{{ pathto('getting-started') }}">Get started</a></li>
|
||||
<li><a href="{{ pathto('how-to/index') }}">How-to guides</a></li>
|
||||
<li><a href="{{ pathto('reference/index') }}">Reference guides</a></li>
|
||||
<li><a href="{{ pathto('explanation/index') }}">Explanation</a></li>
|
||||
<li><a href="{{ pathto('contents') }}">Complete table of contents</a></li>
|
||||
<li><a href="{{ pathto('example/index') }}">Library of examples</a></li>
|
||||
</ul>
|
||||
|
||||
<h3>About the project</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="{{ pathto('getting-started') }}">Install</a></li>
|
||||
<li><a href="{{ pathto('contents') }}">Contents</a></li>
|
||||
<li><a href="{{ pathto('reference') }}">API Reference</a></li>
|
||||
<li><a href="{{ pathto('example/index') }}">Examples</a></li>
|
||||
<li><a href="{{ pathto('customize') }}">Customize</a></li>
|
||||
<li><a href="{{ pathto('changelog') }}">Changelog</a></li>
|
||||
<li><a href="{{ pathto('contributing') }}">Contributing</a></li>
|
||||
<li><a href="{{ pathto('backwards-compatibility') }}">Backwards Compatibility</a></li>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<ul>
|
||||
<li><a href="https://pypi.org/project/pytest/">pytest @ PyPI</a></li>
|
||||
<li><a href="https://github.com/pytest-dev/pytest/">pytest @ GitHub</a></li>
|
||||
<li><a href="http://plugincompat.herokuapp.com/">3rd party plugins</a></li>
|
||||
<li><a href="https://github.com/pytest-dev/pytest/issues">Issue Tracker</a></li>
|
||||
<li><a href="https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf">PDF Documentation</a>
|
||||
</ul>
|
||||
|
||||
@@ -6,6 +6,7 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-6.2.5
|
||||
release-6.2.4
|
||||
release-6.2.3
|
||||
release-6.2.2
|
||||
|
||||
@@ -24,7 +24,7 @@ If you want to install or upgrade pytest, just type one of::
|
||||
easy_install -U pytest
|
||||
|
||||
best,
|
||||
holger krekel / https://merlinux.eu/
|
||||
holger krekel / http://merlinux.eu
|
||||
|
||||
Changes between 2.0.3 and 2.1.0
|
||||
----------------------------------------------
|
||||
|
||||
@@ -20,7 +20,7 @@ If you want to install or upgrade pytest, just type one of::
|
||||
easy_install -U pytest
|
||||
|
||||
best,
|
||||
holger krekel / https://merlinux.eu/
|
||||
holger krekel / http://merlinux.eu
|
||||
|
||||
Changes between 2.1.0 and 2.1.1
|
||||
----------------------------------------------
|
||||
|
||||
@@ -19,7 +19,7 @@ If you want to install or upgrade pytest, just type one of::
|
||||
easy_install -U pytest
|
||||
|
||||
best,
|
||||
holger krekel / https://merlinux.eu/
|
||||
holger krekel / http://merlinux.eu
|
||||
|
||||
Changes between 2.1.1 and 2.1.2
|
||||
----------------------------------------
|
||||
|
||||
30
doc/en/announce/release-6.2.5.rst
Normal file
30
doc/en/announce/release-6.2.5.rst
Normal file
@@ -0,0 +1,30 @@
|
||||
pytest-6.2.5
|
||||
=======================================
|
||||
|
||||
pytest 6.2.5 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* Brylie Christopher Oxley
|
||||
* Daniel Asztalos
|
||||
* Florian Bruhin
|
||||
* Jason Haugen
|
||||
* MapleCCC
|
||||
* Michał Górny
|
||||
* Miro Hrončok
|
||||
* Ran Benita
|
||||
* Ronny Pfannschmidt
|
||||
* Sylvain Bellemare
|
||||
* Thomas Güttler
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,14 +1,16 @@
|
||||
.. _`assert`:
|
||||
|
||||
How to write and report assertions in tests
|
||||
The writing and reporting of assertions in tests
|
||||
==================================================
|
||||
|
||||
.. _`assertfeedback`:
|
||||
.. _`assert with the assert statement`:
|
||||
.. _`assert`:
|
||||
|
||||
|
||||
Asserting with the ``assert`` statement
|
||||
---------------------------------------------------------
|
||||
|
||||
``pytest`` allows you to use the standard Python ``assert`` for verifying
|
||||
``pytest`` allows you to use the standard python ``assert`` for verifying
|
||||
expectations and values in Python tests. For example, you can write the
|
||||
following:
|
||||
|
||||
@@ -29,7 +31,7 @@ you will see the return value of the function call:
|
||||
|
||||
$ pytest test_assert1.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -96,7 +98,7 @@ and if you need to have access to the actual exception info you may use:
|
||||
f()
|
||||
assert "maximum recursion" in str(excinfo.value)
|
||||
|
||||
``excinfo`` is an :class:`~pytest.ExceptionInfo` instance, which is a wrapper around
|
||||
``excinfo`` is an ``ExceptionInfo`` instance, which is a wrapper around
|
||||
the actual exception raised. The main attributes of interest are
|
||||
``.type``, ``.value`` and ``.traceback``.
|
||||
|
||||
@@ -173,6 +175,8 @@ when it encounters comparisons. For example:
|
||||
.. code-block:: python
|
||||
|
||||
# content of test_assert2.py
|
||||
|
||||
|
||||
def test_set_comparison():
|
||||
set1 = set("1308")
|
||||
set2 = set("8035")
|
||||
@@ -184,7 +188,7 @@ if you run this module:
|
||||
|
||||
$ pytest test_assert2.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
.. _bash_completion:
|
||||
|
||||
How to set up bash completion
|
||||
=============================
|
||||
Setting up bash completion
|
||||
==========================
|
||||
|
||||
When using bash as your shell, ``pytest`` can use argcomplete
|
||||
(https://argcomplete.readthedocs.io/) for auto-completion.
|
||||
@@ -6,7 +6,7 @@ Pytest API and builtin fixtures
|
||||
================================================
|
||||
|
||||
|
||||
Most of the information of this page has been moved over to :ref:`api-reference`.
|
||||
Most of the information of this page has been moved over to :ref:`reference`.
|
||||
|
||||
For information on plugin hooks and objects, see :ref:`plugins`.
|
||||
|
||||
@@ -61,7 +61,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
namespace of doctests.
|
||||
|
||||
pytestconfig [session scope]
|
||||
Session-scoped fixture that returns the :class:`pytest.Config` object.
|
||||
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
|
||||
|
||||
Example::
|
||||
|
||||
@@ -144,14 +144,14 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
recwarn
|
||||
Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.
|
||||
|
||||
See https://docs.python.org/library/warnings.html for information
|
||||
See http://docs.python.org/library/warnings.html for information
|
||||
on warning categories.
|
||||
|
||||
tmpdir_factory [session scope]
|
||||
Return a :class:`pytest.TempdirFactory` instance for the test session.
|
||||
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
|
||||
|
||||
tmp_path_factory [session scope]
|
||||
Return a :class:`pytest.TempPathFactory` instance for the test session.
|
||||
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
|
||||
|
||||
tmpdir
|
||||
Return a temporary directory path object which is unique to each test
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
.. _cache:
|
||||
|
||||
|
||||
How to re-run failed tests and maintain state between test runs
|
||||
===============================================================
|
||||
Cache: working with cross-testrun state
|
||||
=======================================
|
||||
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ If you then run it with ``--lf``:
|
||||
|
||||
$ pytest --lf
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -133,7 +133,7 @@ of ``FF`` and dots):
|
||||
|
||||
$ pytest --ff
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 50 items
|
||||
@@ -277,7 +277,7 @@ You can always peek at the content of the cache using the
|
||||
|
||||
$ pytest --cache-show
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
@@ -358,7 +358,7 @@ filtering:
|
||||
|
||||
$ pytest --cache-show example/*
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
.. _`captures`:
|
||||
|
||||
How to capture stdout/stderr output
|
||||
Capturing of the stdout/stderr output
|
||||
=========================================================
|
||||
|
||||
Default stdout/stderr/stdin capturing behaviour
|
||||
@@ -83,7 +83,7 @@ of the failing function and hide the other one:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -28,6 +28,19 @@ with advance notice in the **Deprecations** section of releases.
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 6.2.5 (2021-08-29)
|
||||
=========================
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- `#8494 <https://github.com/pytest-dev/pytest/issues/8494>`_: Python 3.10 is now supported.
|
||||
|
||||
|
||||
- `#9040 <https://github.com/pytest-dev/pytest/issues/9040>`_: Enable compatibility with ``pluggy 1.0`` or later.
|
||||
|
||||
|
||||
pytest 6.2.4 (2021-05-04)
|
||||
=========================
|
||||
|
||||
@@ -49,7 +62,7 @@ Bug Fixes
|
||||
the ``tmp_path``/``tmpdir`` fixture). Now the directories are created with
|
||||
private permissions.
|
||||
|
||||
pytest used to silenty use a pre-existing ``/tmp/pytest-of-<username>`` directory,
|
||||
pytest used silenty use a pre-existing ``/tmp/pytest-of-<username>`` directory,
|
||||
even if owned by another user. This means another user could pre-create such a
|
||||
directory and gain control of another user's temporary directory. Now such a
|
||||
condition results in an error.
|
||||
@@ -1055,7 +1068,7 @@ Bug Fixes
|
||||
- `#7110 <https://github.com/pytest-dev/pytest/issues/7110>`_: Fixed regression: ``asyncbase.TestCase`` tests are executed correctly again.
|
||||
|
||||
|
||||
- `#7143 <https://github.com/pytest-dev/pytest/issues/7143>`_: Fix ``File.from_parent`` so it forwards extra keyword arguments to the constructor.
|
||||
- `#7143 <https://github.com/pytest-dev/pytest/issues/7143>`_: Fix ``File.from_constructor`` so it forwards extra keyword arguments to the constructor.
|
||||
|
||||
|
||||
- `#7145 <https://github.com/pytest-dev/pytest/issues/7145>`_: Classes with broken ``__getattribute__`` methods are displayed correctly during failures.
|
||||
@@ -3117,12 +3130,12 @@ Features
|
||||
will not issue the warning.
|
||||
|
||||
|
||||
- `#3632 <https://github.com/pytest-dev/pytest/issues/3632>`_: Richer equality comparison introspection on ``AssertionError`` for objects created using `attrs <https://www.attrs.org/en/stable/>`__ or `dataclasses <https://docs.python.org/3/library/dataclasses.html>`_ (Python 3.7+, `backported to 3.6 <https://pypi.org/project/dataclasses>`__).
|
||||
- `#3632 <https://github.com/pytest-dev/pytest/issues/3632>`_: Richer equality comparison introspection on ``AssertionError`` for objects created using `attrs <http://www.attrs.org/en/stable/>`__ or `dataclasses <https://docs.python.org/3/library/dataclasses.html>`_ (Python 3.7+, `backported to 3.6 <https://pypi.org/project/dataclasses>`__).
|
||||
|
||||
|
||||
- `#4278 <https://github.com/pytest-dev/pytest/issues/4278>`_: ``CACHEDIR.TAG`` files are now created inside cache directories.
|
||||
|
||||
Those files are part of the `Cache Directory Tagging Standard <https://bford.info/cachedir/spec.html>`__, and can
|
||||
Those files are part of the `Cache Directory Tagging Standard <http://www.bford.info/cachedir/spec.html>`__, and can
|
||||
be used by backup or synchronization programs to identify pytest's cache directory as such.
|
||||
|
||||
|
||||
@@ -5106,7 +5119,7 @@ Improved Documentation
|
||||
|
||||
- In one of the simple examples, use ``pytest_collection_modifyitems()`` to skip
|
||||
tests based on a command-line option, allowing its sharing while preventing a
|
||||
user error when accessing ``pytest.config`` before the argument parsing.
|
||||
user error when acessing ``pytest.config`` before the argument parsing.
|
||||
(`#2653 <https://github.com/pytest-dev/pytest/issues/2653>`_)
|
||||
|
||||
|
||||
@@ -5518,7 +5531,7 @@ Changes
|
||||
Thanks `@ojii`_ for the PR.
|
||||
|
||||
* Replace minor/patch level version numbers in the documentation with placeholders.
|
||||
This significantly reduces change-noise as different contributors regenerate
|
||||
This significantly reduces change-noise as different contributors regnerate
|
||||
the documentation on different platforms.
|
||||
Thanks `@RonnyPfannschmidt`_ for the PR.
|
||||
|
||||
@@ -8475,7 +8488,7 @@ Bug fixes:
|
||||
|
||||
- fixes for making the jython/win32 combination work, note however:
|
||||
jython2.5.1/win32 does not provide a command line launcher, see
|
||||
https://bugs.jython.org/issue1491 . See pylib install documentation
|
||||
http://bugs.jython.org/issue1491 . See pylib install documentation
|
||||
for how to work around.
|
||||
|
||||
- fixes for handling of unicode exception values and unprintable objects
|
||||
|
||||
@@ -35,7 +35,6 @@ release = ".".join(version.split(".")[:2])
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
autodoc_member_order = "bysource"
|
||||
autodoc_typehints = "description"
|
||||
todo_include_todos = 1
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
@@ -71,7 +70,7 @@ master_doc = "contents"
|
||||
|
||||
# General information about the project.
|
||||
project = "pytest"
|
||||
copyright = "2015–2021, holger krekel and pytest-dev team"
|
||||
copyright = "2015–2020, holger krekel and pytest-dev team"
|
||||
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
@@ -160,7 +159,7 @@ html_short_title = "pytest-%s" % release
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
html_logo = "img/pytest_logo_curves.svg"
|
||||
html_logo = "img/pytest1.png"
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
@@ -252,7 +251,7 @@ latex_documents = [
|
||||
"contents",
|
||||
"pytest.tex",
|
||||
"pytest Documentation",
|
||||
"holger krekel, trainer and consultant, https://merlinux.eu/",
|
||||
"holger krekel, trainer and consultant, http://merlinux.eu",
|
||||
"manual",
|
||||
)
|
||||
]
|
||||
@@ -293,7 +292,7 @@ man_pages = [("usage", "pytest", "pytest usage", ["holger krekel at merlinux eu"
|
||||
epub_title = "pytest"
|
||||
epub_author = "holger krekel at merlinux eu"
|
||||
epub_publisher = "holger krekel at merlinux eu"
|
||||
epub_copyright = "2013-2021, holger krekel et alii"
|
||||
epub_copyright = "2013-2020, holger krekel et alii"
|
||||
|
||||
# The language of the text. It defaults to the language option
|
||||
# or en if the language is not set.
|
||||
|
||||
@@ -7,9 +7,9 @@ Contact channels
|
||||
|
||||
- `pytest issue tracker`_ to report bugs or suggest features (for version
|
||||
2.0 and above).
|
||||
|
||||
- `pytest discussions`_ at github for general questions.
|
||||
- `pytest on stackoverflow.com <http://stackoverflow.com/search?q=pytest>`_
|
||||
to post questions with the tag ``pytest``. New Questions will usually
|
||||
to post precise questions with the tag ``pytest``. New Questions will usually
|
||||
be seen by pytest users or developers and answered quickly.
|
||||
|
||||
- `Testing In Python`_: a mailing list for Python testing tools and discussion.
|
||||
@@ -31,19 +31,21 @@ Contact channels
|
||||
consulting.
|
||||
|
||||
.. _`pytest issue tracker`: https://github.com/pytest-dev/pytest/issues
|
||||
.. _`old issue tracker`: https://bitbucket.org/hpk42/py-trunk/issues/
|
||||
.. _`old issue tracker`: http://bitbucket.org/hpk42/py-trunk/issues/
|
||||
|
||||
.. _`merlinux.eu`: https://merlinux.eu/
|
||||
.. _`pytest discussions`: https://github.com/pytest-dev/pytest/discussions
|
||||
|
||||
.. _`merlinux.eu`: http://merlinux.eu
|
||||
|
||||
.. _`get an account`:
|
||||
|
||||
.. _tetamap: https://tetamap.wordpress.com/
|
||||
.. _tetamap: http://tetamap.wordpress.com
|
||||
|
||||
.. _`@pylibcommit`: https://twitter.com/pylibcommit
|
||||
.. _`@pylibcommit`: http://twitter.com/pylibcommit
|
||||
|
||||
|
||||
.. _`Testing in Python`: http://lists.idyll.org/listinfo/testing-in-python
|
||||
.. _FOAF: https://en.wikipedia.org/wiki/FOAF
|
||||
.. _FOAF: http://en.wikipedia.org/wiki/FOAF
|
||||
.. _`py-dev`:
|
||||
.. _`development mailing list`:
|
||||
.. _`pytest-dev at python.org (mailing list)`: http://mail.python.org/mailman/listinfo/pytest-dev
|
||||
|
||||
@@ -7,81 +7,37 @@ Full pytest documentation
|
||||
|
||||
.. `Download latest version as EPUB <http://media.readthedocs.org/epub/pytest/latest/pytest.epub>`_
|
||||
|
||||
|
||||
Start here
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
getting-started
|
||||
usage
|
||||
existingtestsuite
|
||||
assert
|
||||
fixture
|
||||
mark
|
||||
monkeypatch
|
||||
tmpdir
|
||||
capture
|
||||
warnings
|
||||
doctest
|
||||
skipping
|
||||
parametrize
|
||||
cache
|
||||
unittest
|
||||
nose
|
||||
xunit_setup
|
||||
plugins
|
||||
writing_plugins
|
||||
logging
|
||||
reference
|
||||
|
||||
|
||||
How-to guides
|
||||
-------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
how-to/usage
|
||||
how-to/assert
|
||||
how-to/fixtures
|
||||
how-to/mark
|
||||
how-to/parametrize
|
||||
how-to/tmpdir
|
||||
how-to/monkeypatch
|
||||
how-to/doctest
|
||||
how-to/cache
|
||||
|
||||
how-to/logging
|
||||
how-to/capture-stdout-stderr
|
||||
how-to/capture-warnings
|
||||
how-to/skipping
|
||||
|
||||
how-to/plugins
|
||||
how-to/writing_plugins
|
||||
how-to/writing_hook_functions
|
||||
|
||||
how-to/existingtestsuite
|
||||
how-to/unittest
|
||||
how-to/nose
|
||||
how-to/xunit_setup
|
||||
|
||||
how-to/bash-completion
|
||||
|
||||
|
||||
Reference guides
|
||||
-----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
reference/fixtures
|
||||
reference/plugin_list
|
||||
reference/customize
|
||||
reference/reference
|
||||
|
||||
|
||||
Explanation
|
||||
-----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
explanation/anatomy
|
||||
explanation/fixtures
|
||||
explanation/goodpractices
|
||||
explanation/flaky
|
||||
explanation/pythonpath
|
||||
|
||||
|
||||
Further topics
|
||||
-----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
goodpractices
|
||||
flaky
|
||||
pythonpath
|
||||
customize
|
||||
example/index
|
||||
bash-completion
|
||||
|
||||
backwards-compatibility
|
||||
deprecations
|
||||
@@ -95,7 +51,6 @@ Further topics
|
||||
license
|
||||
contact
|
||||
|
||||
history
|
||||
historical-notes
|
||||
talks
|
||||
projects
|
||||
|
||||
@@ -145,8 +145,6 @@ Finding the ``rootdir``
|
||||
|
||||
Here is the algorithm which finds the rootdir from ``args``:
|
||||
|
||||
- If ``-c`` is passed in the command-line, use that as configuration file, and its directory as ``rootdir``.
|
||||
|
||||
- Determine the common ancestor directory for the specified ``args`` that are
|
||||
recognised as paths that exist in the file system. If no such paths are
|
||||
found, the common ancestor directory is set to the current working directory.
|
||||
@@ -162,7 +160,7 @@ Here is the algorithm which finds the rootdir from ``args``:
|
||||
``setup.cfg`` in each of the specified ``args`` and upwards. If one is
|
||||
matched, it becomes the ``configfile`` and its directory becomes the ``rootdir``.
|
||||
|
||||
- If no ``configfile`` was found and no configuration argument is passed, use the already determined common ancestor as root
|
||||
- If no ``configfile`` was found, use the already determined common ancestor as root
|
||||
directory. This allows the use of pytest in structures that are not part of
|
||||
a package and don't have any particular configuration file.
|
||||
|
||||
@@ -179,12 +177,12 @@ Files will only be matched for configuration if:
|
||||
The files are considered in the order above. Options from multiple ``configfiles`` candidates
|
||||
are never merged - the first match wins.
|
||||
|
||||
The :class:`Config <pytest.Config>` object (accessible via hooks or through the :fixture:`pytestconfig` fixture)
|
||||
The internal :class:`Config <_pytest.config.Config>` object (accessible via hooks or through the :fixture:`pytestconfig` fixture)
|
||||
will subsequently carry these attributes:
|
||||
|
||||
- :attr:`config.rootpath <pytest.Config.rootpath>`: the determined root directory, guaranteed to exist.
|
||||
- :attr:`config.rootpath <_pytest.config.Config.rootpath>`: the determined root directory, guaranteed to exist.
|
||||
|
||||
- :attr:`config.inipath <pytest.Config.inipath>`: the determined ``configfile``, may be ``None``
|
||||
- :attr:`config.inipath <_pytest.config.Config.inipath>`: the determined ``configfile``, may be ``None``
|
||||
(it is named ``inipath`` for historical reasons).
|
||||
|
||||
.. versionadded:: 6.1
|
||||
@@ -18,71 +18,6 @@ Deprecated Features
|
||||
Below is a complete list of all pytest features which are considered deprecated. Using those features will issue
|
||||
:class:`PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
|
||||
|
||||
|
||||
``py.path.local`` arguments for hooks replaced with ``pathlib.Path``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In order to support the transition to :mod:`pathlib`, the following hooks now receive additional arguments:
|
||||
|
||||
* :func:`pytest_ignore_collect(fspath: pathlib.Path) <_pytest.hookspec.pytest_ignore_collect>`
|
||||
* :func:`pytest_collect_file(fspath: pathlib.Path) <_pytest.hookspec.pytest_collect_file>`
|
||||
* :func:`pytest_pycollect_makemodule(fspath: pathlib.Path) <_pytest.hookspec.pytest_pycollect_makemodule>`
|
||||
* :func:`pytest_report_header(startpath: pathlib.Path) <_pytest.hookspec.pytest_report_header>`
|
||||
* :func:`pytest_report_collectionfinish(startpath: pathlib.Path) <_pytest.hookspec.pytest_report_collectionfinish>`
|
||||
|
||||
The accompanying ``py.path.local`` based paths have been deprecated: plugins which manually invoke those hooks should only pass the new ``pathlib.Path`` arguments, and users should change their hook implementations to use the new ``pathlib.Path`` arguments.
|
||||
|
||||
|
||||
``Node.fspath`` in favor of ``pathlib`` and ``Node.path``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.3
|
||||
|
||||
As pytest tries to move off `py.path.local <https://py.readthedocs.io/en/latest/path.html>`__ we ported most of the node internals to :mod:`pathlib`.
|
||||
|
||||
Pytest will provide compatibility for quite a while.
|
||||
|
||||
Diamond inheritance between :class:`pytest.File` and :class:`pytest.Item`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.3
|
||||
|
||||
Inheriting from both Item and file at once has never been supported officially,
|
||||
however some plugins providing linting/code analysis have been using this as a hack.
|
||||
|
||||
This practice is now officially deprecated and a common way to fix this is `example pr fixing inheritance`_.
|
||||
|
||||
|
||||
|
||||
.. _example pr fixing inheritance: https://github.com/asmeurer/pytest-flakes/pull/40/files
|
||||
|
||||
|
||||
Backward compatibilities in ``Parser.addoption``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 2.4
|
||||
|
||||
Several behaviors of :meth:`Parser.addoption <pytest.Parser.addoption>` are now
|
||||
scheduled for removal in pytest 7 (deprecated since pytest 2.4.0):
|
||||
|
||||
- ``parser.addoption(..., help=".. %default ..")`` - use ``%(default)s`` instead.
|
||||
- ``parser.addoption(..., type="int/string/float/complex")`` - use ``type=int`` etc. instead.
|
||||
|
||||
|
||||
Raising ``unittest.SkipTest`` during collection
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.3
|
||||
|
||||
Raising :class:`unittest.SkipTest` to skip collection of tests during the
|
||||
pytest collection phase is deprecated. Use :func:`pytest.skip` instead.
|
||||
|
||||
Note: This deprecation only relates to using `unittest.SkipTest` during test
|
||||
collection. You are probably not doing that. Ordinary usage of
|
||||
:class:`unittest.SkipTest` / :meth:`unittest.TestCase.skipTest` /
|
||||
:func:`unittest.skip` in unittest test cases is fully supported.
|
||||
|
||||
|
||||
The ``--strict`` command-line option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -462,8 +397,8 @@ Metafunc.addcall
|
||||
|
||||
.. versionremoved:: 4.0
|
||||
|
||||
``Metafunc.addcall`` was a precursor to the current parametrized mechanism. Users should use
|
||||
:meth:`pytest.Metafunc.parametrize` instead.
|
||||
``_pytest.python.Metafunc.addcall`` was a precursor to the current parametrized mechanism. Users should use
|
||||
:meth:`_pytest.python.Metafunc.parametrize` instead.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
.. _doctest:
|
||||
|
||||
How to run doctests
|
||||
Doctest integration for modules and test files
|
||||
=========================================================
|
||||
|
||||
By default, all files matching the ``test*.txt`` pattern will
|
||||
@@ -30,7 +29,7 @@ then you can just invoke ``pytest`` directly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -49,7 +48,7 @@ and functions, including from test modules:
|
||||
|
||||
# content of mymodule.py
|
||||
def something():
|
||||
"""a doctest in a docstring
|
||||
""" a doctest in a docstring
|
||||
>>> something()
|
||||
42
|
||||
"""
|
||||
@@ -59,7 +58,7 @@ and functions, including from test modules:
|
||||
|
||||
$ pytest --doctest-modules
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -194,7 +193,7 @@ It is possible to use fixtures using the ``getfixture`` helper:
|
||||
.. code-block:: text
|
||||
|
||||
# content of example.rst
|
||||
>>> tmp = getfixture('tmp_path')
|
||||
>>> tmp = getfixture('tmpdir')
|
||||
>>> ...
|
||||
>>>
|
||||
|
||||
@@ -5,9 +5,9 @@ failure_demo = os.path.join(os.path.dirname(__file__), "failure_demo.py")
|
||||
pytest_plugins = ("pytester",)
|
||||
|
||||
|
||||
def test_failure_demo_fails_properly(pytester):
|
||||
target = pytester.path.joinpath(os.path.basename(failure_demo))
|
||||
def test_failure_demo_fails_properly(testdir):
|
||||
target = testdir.tmpdir.join(os.path.basename(failure_demo))
|
||||
shutil.copy(failure_demo, target)
|
||||
result = pytester.runpytest(target, syspathinsert=True)
|
||||
result = testdir.runpytest(target, syspathinsert=True)
|
||||
result.stdout.fnmatch_lines(["*44 failed*"])
|
||||
assert result.ret != 0
|
||||
|
||||
@@ -13,12 +13,12 @@ answers.
|
||||
|
||||
For basic examples, see
|
||||
|
||||
- :ref:`get-started` for basic introductory examples
|
||||
- :doc:`../getting-started` for basic introductory examples
|
||||
- :ref:`assert` for basic assertion examples
|
||||
- :ref:`Fixtures <fixtures>` for basic fixture/setup examples
|
||||
- :ref:`parametrize` for basic test function parametrization
|
||||
- :ref:`unittest` for basic unittest integration
|
||||
- :ref:`noseintegration` for basic nosetests integration
|
||||
- :doc:`../unittest` for basic unittest integration
|
||||
- :doc:`../nose` for basic nosetests integration
|
||||
|
||||
The following examples aim at various use cases you might encounter.
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ You can then restrict a test run to only run tests marked with ``webtest``:
|
||||
|
||||
$ pytest -v -m webtest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 3 deselected / 1 selected
|
||||
@@ -60,7 +60,7 @@ Or the inverse, running all tests except the webtest ones:
|
||||
|
||||
$ pytest -v -m "not webtest"
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 1 deselected / 3 selected
|
||||
@@ -82,7 +82,7 @@ tests based on their module, class, method, or function name:
|
||||
|
||||
$ pytest -v test_server.py::TestClass::test_method
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
@@ -97,7 +97,7 @@ You can also select on the class:
|
||||
|
||||
$ pytest -v test_server.py::TestClass
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
@@ -112,7 +112,7 @@ Or select multiple nodes:
|
||||
|
||||
$ pytest -v test_server.py::TestClass test_server.py::test_send_http
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 2 items
|
||||
@@ -156,7 +156,7 @@ The expression matching is now case-insensitive.
|
||||
|
||||
$ pytest -v -k http # running with the above defined example module
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 3 deselected / 1 selected
|
||||
@@ -171,7 +171,7 @@ And you can also run all tests except the ones that match the keyword:
|
||||
|
||||
$ pytest -k "not send_http" -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 1 deselected / 3 selected
|
||||
@@ -188,7 +188,7 @@ Or to select "http" and "quick" tests:
|
||||
|
||||
$ pytest -k "http or quick" -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 2 deselected / 2 selected
|
||||
@@ -397,7 +397,7 @@ the test needs:
|
||||
|
||||
$ pytest -E stage2
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -412,7 +412,7 @@ and here is one that specifies exactly the environment needed:
|
||||
|
||||
$ pytest -E stage1
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -605,7 +605,7 @@ then you will see two tests skipped and two executed tests as expected:
|
||||
|
||||
$ pytest -rs # this option reports skip reasons
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
@@ -622,7 +622,7 @@ Note that if you specify a platform via the marker-command line option like this
|
||||
|
||||
$ pytest -m linux
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 3 deselected / 1 selected
|
||||
@@ -686,7 +686,7 @@ We can now use the ``-m option`` to select one set:
|
||||
|
||||
$ pytest -m interface --tb=short
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 2 deselected / 2 selected
|
||||
@@ -713,7 +713,7 @@ or to select both "event" and "interface" tests:
|
||||
|
||||
$ pytest -m "interface or event" --tb=short
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 1 deselected / 3 selected
|
||||
|
||||
@@ -12,8 +12,8 @@ pythonlist = ["python3.5", "python3.6", "python3.7"]
|
||||
|
||||
|
||||
@pytest.fixture(params=pythonlist)
|
||||
def python1(request, tmp_path):
|
||||
picklefile = tmp_path / "data.pickle"
|
||||
def python1(request, tmpdir):
|
||||
picklefile = tmpdir.join("data.pickle")
|
||||
return Python(request.param, picklefile)
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ class Python:
|
||||
self.picklefile = picklefile
|
||||
|
||||
def dumps(self, obj):
|
||||
dumpfile = self.picklefile.with_name("dump.py")
|
||||
dumpfile.write_text(
|
||||
dumpfile = self.picklefile.dirpath("dump.py")
|
||||
dumpfile.write(
|
||||
textwrap.dedent(
|
||||
r"""
|
||||
import pickle
|
||||
@@ -46,8 +46,8 @@ class Python:
|
||||
subprocess.check_call((self.pythonpath, str(dumpfile)))
|
||||
|
||||
def load_and_is_true(self, expression):
|
||||
loadfile = self.picklefile.with_name("load.py")
|
||||
loadfile.write_text(
|
||||
loadfile = self.picklefile.dirpath("load.py")
|
||||
loadfile.write(
|
||||
textwrap.dedent(
|
||||
r"""
|
||||
import pickle
|
||||
|
||||
@@ -29,7 +29,7 @@ now execute the test specification:
|
||||
|
||||
nonpython $ pytest test_simple.yaml
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collected 2 items
|
||||
@@ -66,7 +66,7 @@ consulted when reporting in ``verbose`` mode:
|
||||
|
||||
nonpython $ pytest -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collecting ... collected 2 items
|
||||
@@ -92,7 +92,7 @@ interesting to just look at the collection tree:
|
||||
|
||||
nonpython $ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collected 2 items
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_collect_file(parent, fspath):
|
||||
if fspath.suffix == ".yaml" and fspath.name.startswith("test"):
|
||||
return YamlFile.from_parent(parent, path=fspath)
|
||||
def pytest_collect_file(parent, path):
|
||||
if path.ext == ".yaml" and path.basename.startswith("test"):
|
||||
return YamlFile.from_parent(parent, fspath=path)
|
||||
|
||||
|
||||
class YamlFile(pytest.File):
|
||||
@@ -12,7 +12,7 @@ class YamlFile(pytest.File):
|
||||
# We need a yaml parser, e.g. PyYAML.
|
||||
import yaml
|
||||
|
||||
raw = yaml.safe_load(self.path.open())
|
||||
raw = yaml.safe_load(self.fspath.open())
|
||||
for name, spec in sorted(raw.items()):
|
||||
yield YamlItem.from_parent(self, name=name, spec=spec)
|
||||
|
||||
|
||||
@@ -97,10 +97,10 @@ the argument name:
|
||||
|
||||
# content of test_time.py
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
testdata = [
|
||||
(datetime(2001, 12, 12), datetime(2001, 12, 11), timedelta(1)),
|
||||
(datetime(2001, 12, 11), datetime(2001, 12, 12), timedelta(-1)),
|
||||
@@ -160,7 +160,7 @@ objects, they are still using the default pytest representation:
|
||||
|
||||
$ pytest test_time.py --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 8 items
|
||||
@@ -225,7 +225,7 @@ this is a fully self-contained example which you can run with:
|
||||
|
||||
$ pytest test_scenarios.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
@@ -240,7 +240,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
|
||||
|
||||
$ pytest --collect-only test_scenarios.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
@@ -319,7 +319,7 @@ Let's first see how it looks like at collection time:
|
||||
|
||||
$ pytest test_backends.py --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -418,7 +418,7 @@ The result of this test will be successful:
|
||||
|
||||
$ pytest -v test_indirect_list.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
@@ -573,7 +573,7 @@ If you run this with reporting for skips enabled:
|
||||
|
||||
$ pytest -rs test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -635,7 +635,7 @@ Then run ``pytest`` with verbose mode and with only the ``basic`` marker:
|
||||
|
||||
$ pytest -v -m basic
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 24 items / 21 deselected / 3 selected
|
||||
|
||||
@@ -147,7 +147,7 @@ The test collection would look like this:
|
||||
|
||||
$ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 2 items
|
||||
@@ -209,7 +209,7 @@ You can always peek at the collection tree without running tests like this:
|
||||
|
||||
. $ pytest --collect-only pythoncollection.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 3 items
|
||||
@@ -291,7 +291,7 @@ file will be left out:
|
||||
|
||||
$ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 0 items
|
||||
|
||||
@@ -9,7 +9,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
|
||||
assertion $ pytest failure_demo.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/assertion
|
||||
collected 44 items
|
||||
|
||||
@@ -69,7 +69,7 @@ Here is a basic pattern to achieve this:
|
||||
|
||||
|
||||
For this to work we need to add a command line option and
|
||||
provide the ``cmdopt`` through a :ref:`fixture function <fixture>`:
|
||||
provide the ``cmdopt`` through a :ref:`fixture function <fixture function>`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -139,66 +139,10 @@ And now with supplying a command line option:
|
||||
FAILED test_sample.py::test_answer - assert 0
|
||||
1 failed in 0.12s
|
||||
|
||||
You can see that the command line option arrived in our test.
|
||||
|
||||
We could add simple validation for the input by listing the choices:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of conftest.py
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--cmdopt",
|
||||
action="store",
|
||||
default="type1",
|
||||
help="my option: type1 or type2",
|
||||
choices=("type1", "type2"),
|
||||
)
|
||||
|
||||
Now we'll get feedback on a bad argument:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest -q --cmdopt=type3
|
||||
ERROR: usage: pytest [options] [file_or_dir] [file_or_dir] [...]
|
||||
pytest: error: argument --cmdopt: invalid choice: 'type3' (choose from 'type1', 'type2')
|
||||
|
||||
If you need to provide more detailed error messages, you can use the
|
||||
``type`` parameter and raise ``pytest.UsageError``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of conftest.py
|
||||
import pytest
|
||||
|
||||
|
||||
def type_checker(value):
|
||||
msg = "cmdopt must specify a numeric type as typeNNN"
|
||||
if not value.startswith("type"):
|
||||
raise pytest.UsageError(msg)
|
||||
try:
|
||||
int(value[4:])
|
||||
except ValueError:
|
||||
raise pytest.UsageError(msg)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--cmdopt",
|
||||
action="store",
|
||||
default="type1",
|
||||
help="my option: type1 or type2",
|
||||
type=type_checker,
|
||||
)
|
||||
|
||||
This completes the basic pattern. However, one often rather wants to
|
||||
process command line options outside of the test and rather pass in
|
||||
different or more complex objects.
|
||||
You can see that the command line option arrived in our test. This
|
||||
completes the basic pattern. However, one often rather wants to process
|
||||
command line options outside of the test and rather pass in different or
|
||||
more complex objects.
|
||||
|
||||
Dynamically adding command line options
|
||||
--------------------------------------------------------------
|
||||
@@ -231,7 +175,7 @@ directory with the above conftest.py:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 0 items
|
||||
@@ -296,7 +240,7 @@ and when running it will see a skipped "slow" test:
|
||||
|
||||
$ pytest -rs # "-rs" means report details on the little 's'
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -313,7 +257,7 @@ Or run it including the ``slow`` marked test:
|
||||
|
||||
$ pytest --runslow
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -457,7 +401,7 @@ which will add the string to the test header accordingly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
project deps: mylib-1.1
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
@@ -486,7 +430,7 @@ which will add info only when run with "--v":
|
||||
|
||||
$ pytest -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
info1: did you know that ...
|
||||
did you?
|
||||
@@ -501,7 +445,7 @@ and nothing when run plainly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 0 items
|
||||
@@ -541,7 +485,7 @@ Now we can profile which test functions execute the slowest:
|
||||
|
||||
$ pytest --durations=3
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
@@ -647,7 +591,7 @@ If we run this:
|
||||
|
||||
$ pytest -rx
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
@@ -677,7 +621,7 @@ Package/Directory-level fixtures (setups)
|
||||
-------------------------------------------------------
|
||||
|
||||
If you have nested test directories, you can have per-directory fixture scopes
|
||||
by placing fixture functions in a ``conftest.py`` file in that directory.
|
||||
by placing fixture functions in a ``conftest.py`` file in that directory
|
||||
You can use all types of fixtures including :ref:`autouse fixtures
|
||||
<autouse fixtures>` which are the equivalent of xUnit's setup/teardown
|
||||
concept. It's however recommended to have explicit fixture references in your
|
||||
@@ -731,7 +675,7 @@ We can run this:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 7 items
|
||||
@@ -824,8 +768,8 @@ case we just write some information out to a ``failures`` file:
|
||||
mode = "a" if os.path.exists("failures") else "w"
|
||||
with open("failures", mode) as f:
|
||||
# let's also access a fixture for the fun of it
|
||||
if "tmp_path" in item.fixturenames:
|
||||
extra = " ({})".format(item.funcargs["tmp_path"])
|
||||
if "tmpdir" in item.fixturenames:
|
||||
extra = " ({})".format(item.funcargs["tmpdir"])
|
||||
else:
|
||||
extra = ""
|
||||
|
||||
@@ -837,7 +781,7 @@ if you then have failing tests:
|
||||
.. code-block:: python
|
||||
|
||||
# content of test_module.py
|
||||
def test_fail1(tmp_path):
|
||||
def test_fail1(tmpdir):
|
||||
assert 0
|
||||
|
||||
|
||||
@@ -850,7 +794,7 @@ and run them:
|
||||
|
||||
$ pytest test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -860,9 +804,9 @@ and run them:
|
||||
================================= FAILURES =================================
|
||||
________________________________ test_fail1 ________________________________
|
||||
|
||||
tmp_path = Path('PYTEST_TMPDIR/test_fail10')
|
||||
tmpdir = local('PYTEST_TMPDIR/test_fail10')
|
||||
|
||||
def test_fail1(tmp_path):
|
||||
def test_fail1(tmpdir):
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
@@ -957,7 +901,7 @@ and run it:
|
||||
|
||||
$ pytest -s test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
@@ -1068,7 +1012,7 @@ your frozen program work as the pytest runner by some clever
|
||||
argument handling during program startup. This allows you to
|
||||
have a single executable, which is usually more convenient.
|
||||
Please note that the mechanism for plugin discovery used by pytest
|
||||
(setuptools entry points) doesn't work with frozen executables so pytest
|
||||
(setupttools entry points) doesn't work with frozen executables so pytest
|
||||
can't find any third party plugins automatically. To include third party plugins
|
||||
like ``pytest-timeout`` they must be imported explicitly and passed on to pytest.main.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.. _existingtestsuite:
|
||||
|
||||
How to use pytest with an existing test suite
|
||||
==============================================
|
||||
Using pytest with an existing test suite
|
||||
===========================================
|
||||
|
||||
Pytest can be used with most existing test suites, but its
|
||||
behavior differs from other test runners such as :ref:`nose <noseintegration>` or
|
||||
@@ -1,46 +0,0 @@
|
||||
.. _test-anatomy:
|
||||
|
||||
Anatomy of a test
|
||||
=================
|
||||
|
||||
In the simplest terms, a test is meant to look at the result of a particular
|
||||
behavior, and make sure that result aligns with what you would expect.
|
||||
Behavior is not something that can be empirically measured, which is why writing
|
||||
tests can be challenging.
|
||||
|
||||
"Behavior" is the way in which some system **acts in response** to a particular
|
||||
situation and/or stimuli. But exactly *how* or *why* something is done is not
|
||||
quite as important as *what* was done.
|
||||
|
||||
You can think of a test as being broken down into four steps:
|
||||
|
||||
1. **Arrange**
|
||||
2. **Act**
|
||||
3. **Assert**
|
||||
4. **Cleanup**
|
||||
|
||||
**Arrange** is where we prepare everything for our test. This means pretty
|
||||
much everything except for the "**act**". It's lining up the dominoes so that
|
||||
the **act** can do its thing in one, state-changing step. This can mean
|
||||
preparing objects, starting/killing services, entering records into a database,
|
||||
or even things like defining a URL to query, generating some credentials for a
|
||||
user that doesn't exist yet, or just waiting for some process to finish.
|
||||
|
||||
**Act** is the singular, state-changing action that kicks off the **behavior**
|
||||
we want to test. This behavior is what carries out the changing of the state of
|
||||
the system under test (SUT), and it's the resulting changed state that we can
|
||||
look at to make a judgement about the behavior. This typically takes the form of
|
||||
a function/method call.
|
||||
|
||||
**Assert** is where we look at that resulting state and check if it looks how
|
||||
we'd expect after the dust has settled. It's where we gather evidence to say the
|
||||
behavior does or does not aligns with what we expect. The ``assert`` in our test
|
||||
is where we take that measurement/observation and apply our judgement to it. If
|
||||
something should be green, we'd say ``assert thing == "green"``.
|
||||
|
||||
**Cleanup** is where the test picks up after itself, so other tests aren't being
|
||||
accidentally influenced by it.
|
||||
|
||||
At its core, the test is ultimately the **act** and **assert** steps, with the
|
||||
**arrange** step only providing the context. **Behavior** exists between **act**
|
||||
and **assert**.
|
||||
@@ -1,158 +0,0 @@
|
||||
.. _about-fixtures:
|
||||
|
||||
About fixtures
|
||||
===============
|
||||
|
||||
.. seealso:: :ref:`how-to-fixtures`
|
||||
.. seealso:: :ref:`Fixtures reference <reference-fixtures>`
|
||||
|
||||
pytest fixtures are designed to be explicit, modular and scalable.
|
||||
|
||||
What fixtures are
|
||||
-----------------
|
||||
|
||||
In testing, a `fixture <https://en.wikipedia.org/wiki/Test_fixture#Software>`_
|
||||
provides a defined, reliable and consistent context for the tests. This could
|
||||
include environment (for example a database configured with known parameters)
|
||||
or content (such as a dataset).
|
||||
|
||||
Fixtures define the steps and data that constitute the *arrange* phase of a
|
||||
test (see :ref:`test-anatomy`). In pytest, they are functions you define that
|
||||
serve this purpose. They can also be used to define a test's *act* phase; this
|
||||
is a powerful technique for designing more complex tests.
|
||||
|
||||
The services, state, or other operating environments set up by fixtures are
|
||||
accessed by test functions through arguments. For each fixture used by a test
|
||||
function there is typically a parameter (named after the fixture) in the test
|
||||
function's definition.
|
||||
|
||||
We can tell pytest that a particular function is a fixture by decorating it with
|
||||
:py:func:`@pytest.fixture <pytest.fixture>`. Here's a simple example of
|
||||
what a fixture in pytest might look like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class Fruit:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.name == other.name
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def my_fruit():
|
||||
return Fruit("apple")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fruit_basket(my_fruit):
|
||||
return [Fruit("banana"), my_fruit]
|
||||
|
||||
|
||||
def test_my_fruit_in_basket(my_fruit, fruit_basket):
|
||||
assert my_fruit in fruit_basket
|
||||
|
||||
Tests don't have to be limited to a single fixture, either. They can depend on
|
||||
as many fixtures as you want, and fixtures can use other fixtures, as well. This
|
||||
is where pytest's fixture system really shines.
|
||||
|
||||
|
||||
Improvements over xUnit-style setup/teardown functions
|
||||
-----------------------------------------------------------
|
||||
|
||||
pytest fixtures offer dramatic improvements over the classic xUnit
|
||||
style of setup/teardown functions:
|
||||
|
||||
* fixtures have explicit names and are activated by declaring their use
|
||||
from test functions, modules, classes or whole projects.
|
||||
|
||||
* fixtures are implemented in a modular manner, as each fixture name
|
||||
triggers a *fixture function* which can itself use other fixtures.
|
||||
|
||||
* fixture management scales from simple unit to complex
|
||||
functional testing, allowing to parametrize fixtures and tests according
|
||||
to configuration and component options, or to re-use fixtures
|
||||
across function, class, module or whole test session scopes.
|
||||
|
||||
* teardown logic can be easily, and safely managed, no matter how many fixtures
|
||||
are used, without the need to carefully handle errors by hand or micromanage
|
||||
the order that cleanup steps are added.
|
||||
|
||||
In addition, pytest continues to support :ref:`xunitsetup`. You can mix
|
||||
both styles, moving incrementally from classic to new style, as you
|
||||
prefer. You can also start out from existing :ref:`unittest.TestCase
|
||||
style <unittest.TestCase>` or :ref:`nose based <nosestyle>` projects.
|
||||
|
||||
|
||||
|
||||
Fixture errors
|
||||
--------------
|
||||
|
||||
pytest does its best to put all the fixtures for a given test in a linear order
|
||||
so that it can see which fixture happens first, second, third, and so on. If an
|
||||
earlier fixture has a problem, though, and raises an exception, pytest will stop
|
||||
executing fixtures for that test and mark the test as having an error.
|
||||
|
||||
When a test is marked as having an error, it doesn't mean the test failed,
|
||||
though. It just means the test couldn't even be attempted because one of the
|
||||
things it depends on had a problem.
|
||||
|
||||
This is one reason why it's a good idea to cut out as many unnecessary
|
||||
dependencies as possible for a given test. That way a problem in something
|
||||
unrelated isn't causing us to have an incomplete picture of what may or may not
|
||||
have issues.
|
||||
|
||||
Here's a quick example to help explain:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def append_first(order):
|
||||
order.append(1)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def append_second(order, append_first):
|
||||
order.extend([2])
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def append_third(order, append_second):
|
||||
order += [3]
|
||||
|
||||
|
||||
def test_order(order):
|
||||
assert order == [1, 2, 3]
|
||||
|
||||
|
||||
If, for whatever reason, ``order.append(1)`` had a bug and it raises an exception,
|
||||
we wouldn't be able to know if ``order.extend([2])`` or ``order += [3]`` would
|
||||
also have problems. After ``append_first`` throws an exception, pytest won't run
|
||||
any more fixtures for ``test_order``, and it won't even try to run
|
||||
``test_order`` itself. The only things that would've run would be ``order`` and
|
||||
``append_first``.
|
||||
|
||||
|
||||
Sharing test data
|
||||
-----------------
|
||||
|
||||
If you want to make test data from files available to your tests, a good way
|
||||
to do this is by loading these data in a fixture for use by your tests.
|
||||
This makes use of the automatic caching mechanisms of pytest.
|
||||
|
||||
Another good approach is by adding the data files in the ``tests`` folder.
|
||||
There are also community plugins available to help to manage this aspect of
|
||||
testing, e.g. `pytest-datadir <https://pypi.org/project/pytest-datadir/>`__
|
||||
and `pytest-datafiles <https://pypi.org/project/pytest-datafiles/>`__.
|
||||
@@ -1,15 +0,0 @@
|
||||
:orphan:
|
||||
|
||||
.. _explanation:
|
||||
|
||||
Explanation
|
||||
================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
anatomy
|
||||
fixtures
|
||||
goodpractices
|
||||
flaky
|
||||
pythonpath
|
||||
File diff suppressed because it is too large
Load Diff
@@ -113,7 +113,7 @@ Resources
|
||||
|
||||
* `Eradicating Non-Determinism in Tests <https://martinfowler.com/articles/nonDeterminism.html>`_ by Martin Fowler, 2011
|
||||
* `No more flaky tests on the Go team <https://www.thoughtworks.com/insights/blog/no-more-flaky-tests-go-team>`_ by Pavan Sudarshan, 2012
|
||||
* `The Build That Cried Broken: Building Trust in your Continuous Integration Tests <https://www.youtube.com/embed/VotJqV4n8ig>`_ talk (video) by `Angie Jones <https://angiejones.tech/>`_ at SeleniumConf Austin 2017
|
||||
* `The Build That Cried Broken: Building Trust in your Continuous Integration Tests <https://www.youtube.com/embed/VotJqV4n8ig>`_ talk (video) by `Angie Jones <http://angiejones.tech/>`_ at SeleniumConf Austin 2017
|
||||
* `Test and Code Podcast: Flaky Tests and How to Deal with Them <https://testandcode.com/50>`_ by Brian Okken and Anthony Shaw, 2018
|
||||
* Microsoft:
|
||||
|
||||
@@ -47,7 +47,7 @@ There are several limitations and difficulties with this approach:
|
||||
2. parametrizing the "db" resource is not straight forward:
|
||||
you need to apply a "parametrize" decorator or implement a
|
||||
:py:func:`~hookspec.pytest_generate_tests` hook
|
||||
calling :py:func:`~pytest.Metafunc.parametrize` which
|
||||
calling :py:func:`~python.Metafunc.parametrize` which
|
||||
performs parametrization at the places where the resource
|
||||
is used. Moreover, you need to modify the factory to use an
|
||||
``extrakey`` parameter containing ``request.param`` to the
|
||||
@@ -113,7 +113,7 @@ This new way of parametrizing funcarg factories should in many cases
|
||||
allow to re-use already written factories because effectively
|
||||
``request.param`` was already used when test functions/classes were
|
||||
parametrized via
|
||||
:py:func:`metafunc.parametrize(indirect=True) <pytest.Metafunc.parametrize>` calls.
|
||||
:py:func:`metafunc.parametrize(indirect=True) <_pytest.python.Metafunc.parametrize>` calls.
|
||||
|
||||
Of course it's perfectly fine to combine parametrization and scoping:
|
||||
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
.. _get-started:
|
||||
|
||||
Get Started
|
||||
Installation and Getting Started
|
||||
===================================
|
||||
|
||||
**Pythons**: Python 3.6, 3.7, 3.8, 3.9, PyPy3
|
||||
|
||||
**Platforms**: Linux and Windows
|
||||
|
||||
**PyPI package name**: `pytest <https://pypi.org/project/pytest/>`_
|
||||
|
||||
**Documentation as PDF**: `download latest <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_
|
||||
|
||||
``pytest`` is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library.
|
||||
|
||||
.. _`getstarted`:
|
||||
.. _`installation`:
|
||||
|
||||
Install ``pytest``
|
||||
----------------------------------------
|
||||
|
||||
``pytest`` requires: Python 3.6, 3.7, 3.8, 3.9, or PyPy3.
|
||||
|
||||
1. Run the following command in your command line:
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -22,14 +28,14 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 6.2.4
|
||||
pytest 6.2.5
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
Create your first test
|
||||
----------------------------------------------------------
|
||||
|
||||
Create a new file called ``test_sample.py``, containing a function, and a test:
|
||||
Create a simple test function with just four lines of code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -41,13 +47,13 @@ Create a new file called ``test_sample.py``, containing a function, and a test:
|
||||
def test_answer():
|
||||
assert func(3) == 5
|
||||
|
||||
The test
|
||||
That’s it. You can now execute the test function:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -71,7 +77,7 @@ The ``[100%]`` refers to the overall progress of running all test cases. After i
|
||||
|
||||
.. note::
|
||||
|
||||
You can use the ``assert`` statement to verify test expectations. pytest’s `Advanced assertion introspection <https://docs.python.org/reference/simple_stmts.html>`_ will intelligently report intermediate values of the assert expression so you can avoid the many names `of JUnit legacy methods <https://docs.python.org/library/unittest.html>`_.
|
||||
You can use the ``assert`` statement to verify test expectations. pytest’s `Advanced assertion introspection <http://docs.python.org/reference/simple_stmts.html#the-assert-statement>`_ will intelligently report intermediate values of the assert expression so you can avoid the many names `of JUnit legacy methods <http://docs.python.org/library/unittest.html#test-cases>`_.
|
||||
|
||||
Run multiple tests
|
||||
----------------------------------------------------------
|
||||
@@ -169,36 +175,40 @@ This is outlined below:
|
||||
|
||||
# content of test_class_demo.py
|
||||
class TestClassDemoInstance:
|
||||
value = 0
|
||||
|
||||
def test_one(self):
|
||||
self.value = 1
|
||||
assert self.value == 1
|
||||
assert 0
|
||||
|
||||
def test_two(self):
|
||||
assert self.value == 1
|
||||
assert 0
|
||||
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest -k TestClassDemoInstance -q
|
||||
.F [100%]
|
||||
FF [100%]
|
||||
================================= FAILURES =================================
|
||||
______________________ TestClassDemoInstance.test_one ______________________
|
||||
|
||||
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef>
|
||||
|
||||
def test_one(self):
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
test_class_demo.py:3: AssertionError
|
||||
______________________ TestClassDemoInstance.test_two ______________________
|
||||
|
||||
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef>
|
||||
|
||||
def test_two(self):
|
||||
> assert self.value == 1
|
||||
E assert 0 == 1
|
||||
E + where 0 = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef>.value
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
test_class_demo.py:9: AssertionError
|
||||
test_class_demo.py:6: AssertionError
|
||||
========================= short test summary info ==========================
|
||||
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0 == 1
|
||||
1 failed, 1 passed in 0.04s
|
||||
|
||||
Note that attributes added at class level are *class attributes*, so they will be shared between tests.
|
||||
FAILED test_class_demo.py::TestClassDemoInstance::test_one - assert 0
|
||||
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0
|
||||
2 failed in 0.12s
|
||||
|
||||
Request a unique temporary directory for functional tests
|
||||
--------------------------------------------------------------
|
||||
@@ -207,24 +217,24 @@ Request a unique temporary directory for functional tests
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of test_tmp_path.py
|
||||
def test_needsfiles(tmp_path):
|
||||
print(tmp_path)
|
||||
# content of test_tmpdir.py
|
||||
def test_needsfiles(tmpdir):
|
||||
print(tmpdir)
|
||||
assert 0
|
||||
|
||||
List the name ``tmp_path`` in the test function signature and ``pytest`` will lookup and call a fixture factory to create the resource before performing the test function call. Before the test runs, ``pytest`` creates a unique-per-test-invocation temporary directory:
|
||||
List the name ``tmpdir`` in the test function signature and ``pytest`` will lookup and call a fixture factory to create the resource before performing the test function call. Before the test runs, ``pytest`` creates a unique-per-test-invocation temporary directory:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest -q test_tmp_path.py
|
||||
$ pytest -q test_tmpdir.py
|
||||
F [100%]
|
||||
================================= FAILURES =================================
|
||||
_____________________________ test_needsfiles ______________________________
|
||||
|
||||
tmp_path = Path('PYTEST_TMPDIR/test_needsfiles0')
|
||||
tmpdir = local('PYTEST_TMPDIR/test_needsfiles0')
|
||||
|
||||
def test_needsfiles(tmp_path):
|
||||
print(tmp_path)
|
||||
def test_needsfiles(tmpdir):
|
||||
print(tmpdir)
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
@@ -232,10 +242,10 @@ List the name ``tmp_path`` in the test function signature and ``pytest`` will lo
|
||||
--------------------------- Captured stdout call ---------------------------
|
||||
PYTEST_TMPDIR/test_needsfiles0
|
||||
========================= short test summary info ==========================
|
||||
FAILED test_tmp_path.py::test_needsfiles - assert 0
|
||||
FAILED test_tmpdir.py::test_needsfiles - assert 0
|
||||
1 failed in 0.12s
|
||||
|
||||
More info on temporary directory handling is available at :ref:`Temporary directories and files <tmpdir handling>`.
|
||||
More info on tmpdir handling is available at :ref:`Temporary directories and files <tmpdir handling>`.
|
||||
|
||||
Find out what kind of builtin :ref:`pytest fixtures <fixtures>` exist with the command:
|
||||
|
||||
@@ -250,7 +260,7 @@ Continue reading
|
||||
|
||||
Check out additional pytest resources to help you customize tests for your unique workflow:
|
||||
|
||||
* ":ref:`usage`" for command line invocation examples
|
||||
* ":ref:`cmdline`" for command line invocation examples
|
||||
* ":ref:`existingtestsuite`" for working with pre-existing tests
|
||||
* ":ref:`mark`" for information on the ``pytest.mark`` mechanism
|
||||
* ":ref:`fixtures`" for providing a functional baseline to your tests
|
||||
|
||||
@@ -48,7 +48,7 @@ Conventions for Python test discovery
|
||||
* ``test`` prefixed test functions or methods outside of class
|
||||
* ``test`` prefixed test functions or methods inside ``Test`` prefixed test classes (without an ``__init__`` method)
|
||||
|
||||
For examples of how to customize your test discovery :doc:`/example/pythoncollection`.
|
||||
For examples of how to customize your test discovery :doc:`example/pythoncollection`.
|
||||
|
||||
Within Python modules, ``pytest`` also discovers tests using the standard
|
||||
:ref:`unittest.TestCase <unittest.TestCase>` subclassing technique.
|
||||
@@ -151,7 +151,7 @@ This layout prevents a lot of common pitfalls and has many benefits, which are b
|
||||
|
||||
.. note::
|
||||
The new ``--import-mode=importlib`` (see :ref:`import-modes`) doesn't have
|
||||
any of the drawbacks above because ``sys.path`` is not changed when importing
|
||||
any of the drawbacks above because ``sys.path`` and ``sys.modules`` are not changed when importing
|
||||
test modules, so users that run
|
||||
into this issue are strongly encouraged to try it and report if the new option works well for them.
|
||||
|
||||
@@ -231,7 +231,7 @@ Note that this layout also works in conjunction with the ``src`` layout mentione
|
||||
|
||||
|
||||
.. _`virtualenv`: https://pypi.org/project/virtualenv/
|
||||
.. _`buildout`: http://www.buildout.org/en/latest/
|
||||
.. _`buildout`: http://www.buildout.org/
|
||||
.. _pip: https://pypi.org/project/pip/
|
||||
|
||||
.. _`use tox`:
|
||||
@@ -240,7 +240,7 @@ tox
|
||||
------
|
||||
|
||||
Once you are done with your work and want to make sure that your actual
|
||||
package passes all tests you may want to look into `tox <https://tox.readthedocs.io/>`_, the
|
||||
package passes all tests you may want to look into `tox`_, the
|
||||
virtualenv test automation tool and its `pytest support
|
||||
<https://tox.readthedocs.io/en/latest/example/pytest.html>`_.
|
||||
tox helps you to setup virtualenv environments with pre-defined
|
||||
@@ -1,147 +0,0 @@
|
||||
History
|
||||
=======
|
||||
|
||||
pytest has a long and interesting history. The `first commit
|
||||
<https://github.com/pytest-dev/pytest/commit/5992a8ef21424d7571305a8d7e2a3431ee7e1e23>`__
|
||||
in this repository is from January 2007, and even that commit alone already
|
||||
tells a lot: The repository originally was from the `py
|
||||
<https://pypi.org/project/py/>`__ library (later split off to pytest), and it
|
||||
originally was a SVN revision, migrated to Mercurial, and finally migrated to
|
||||
git.
|
||||
|
||||
However, the commit says “create the new development trunk” and is
|
||||
already quite big: *435 files changed, 58640 insertions(+)*. This is because
|
||||
pytest originally was born as part of `PyPy <https://www.pypy.org/>`__, to make
|
||||
it easier to write tests for it. Here's how it evolved from there to its own
|
||||
project:
|
||||
|
||||
|
||||
- Late 2002 / early 2003, `PyPy was
|
||||
born <https://morepypy.blogspot.com/2018/09/the-first-15-years-of-pypy.html>`__.
|
||||
- Like that blog post mentioned, from very early on, there was a big
|
||||
focus on testing. There were various ``testsupport`` files on top of
|
||||
unittest.py, and as early as June 2003, Holger Krekel (`@hpk42 <https://github.com/hpk42>`__)
|
||||
`refactored <https://mail.python.org/pipermail/pypy-dev/2003-June/000787.html>`__
|
||||
its test framework to clean things up (``pypy.tool.test``, but still
|
||||
on top of ``unittest.py``, with nothing pytest-like yet).
|
||||
- In December 2003, there was `another
|
||||
iteration <https://foss.heptapod.net/pypy/pypy/-/commit/02752373e1b29d89c6bb0a97e5f940caa22bdd63>`__
|
||||
at improving their testing situation, by Stefan Schwarzer, called
|
||||
``pypy.tool.newtest``.
|
||||
- However, it didn’t seem to be around for long, as around June/July
|
||||
2004, efforts started on a thing called ``utest``, offering plain
|
||||
assertions. This seems like the start of something pytest-like, but
|
||||
unfortunately, it's unclear where the test runner's code was at the time.
|
||||
The closest thing still around is `this
|
||||
file <https://foss.heptapod.net/pypy/pypy/-/commit/0735f9ed287ec20950a7dd0a16fc10810d4f6847>`__,
|
||||
but that doesn’t seem like a complete test runner at all. What can be seen
|
||||
is that there were `various
|
||||
efforts <https://foss.heptapod.net/pypy/pypy/-/commits/branch/default?utf8=%E2%9C%93&search=utest>`__
|
||||
by Laura Creighton and Samuele Pedroni (`@pedronis <https://github.com/pedronis>`__) at automatically
|
||||
converting existing tests to the new ``utest`` framework.
|
||||
- Around the same time, for Europython 2004, @hpk42 `started a
|
||||
project <http://web.archive.org/web/20041020215353/http://codespeak.net/svn/user/hpk/talks/std-talk.txt>`__
|
||||
originally called “std”, intended to be a “complementary standard
|
||||
library” - already laying out the principles behind what later became
|
||||
pytest:
|
||||
|
||||
- current “batteries included” are very useful, but
|
||||
|
||||
- some of them are written in a pretty much java-like style,
|
||||
especially the unittest-framework
|
||||
- […]
|
||||
- the best API is one that doesn’t exist
|
||||
|
||||
[…]
|
||||
|
||||
- a testing package should require as few boilerplate code as
|
||||
possible and offer much flexibility
|
||||
- it should provide premium quality tracebacks and debugging aid
|
||||
|
||||
[…]
|
||||
|
||||
- first of all … forget about limited “assertXYZ APIs” and use the
|
||||
real thing, e.g.::
|
||||
|
||||
assert x == y
|
||||
|
||||
- this works with plain python but you get unhelpful “assertion
|
||||
failed” errors with no information
|
||||
|
||||
- std.utest (magic!) actually reinterprets the assertion expression
|
||||
and offers detailed information about underlying values
|
||||
|
||||
- In September 2004, the ``py-dev`` mailinglist gets born, which `is
|
||||
now <https://mail.python.org/pipermail/pytest-dev/>`__ ``pytest-dev``,
|
||||
but thankfully with all the original archives still intact.
|
||||
|
||||
- Around September/October 2004, the ``std`` project `was renamed
|
||||
<https://mail.python.org/pipermail/pypy-dev/2004-September/001565.html>`__ to
|
||||
``py`` and ``std.utest`` became ``py.test``. This is also the first time the
|
||||
`entire source
|
||||
code <https://foss.heptapod.net/pypy/pypy/-/commit/42cf50c412026028e20acd23d518bd92e623ac11>`__,
|
||||
seems to be available, with much of the API still being around today:
|
||||
|
||||
- ``py.path.local``, which is being phased out of pytest (in favour of
|
||||
pathlib) some 16-17 years later
|
||||
- The idea of the collection tree, including ``Collector``,
|
||||
``FSCollector``, ``Directory``, ``PyCollector``, ``Module``,
|
||||
``Class``
|
||||
- Arguments like ``-x`` / ``--exitfirst``, ``-l`` /
|
||||
``--showlocals``, ``--fulltrace``, ``--pdb``, ``-S`` /
|
||||
``--nocapture`` (``-s`` / ``--capture=off`` today),
|
||||
``--collectonly`` (``--collect-only`` today)
|
||||
|
||||
- In the same month, the ``py`` library `gets split off
|
||||
<https://foss.heptapod.net/pypy/pypy/-/commit/6bdafe9203ad92eb259270b267189141c53bce33>`__
|
||||
from ``PyPy``
|
||||
|
||||
- It seemed to get rather quiet for a while, and little seemed to happen
|
||||
between October 2004 (removing ``py`` from PyPy) and January
|
||||
2007 (first commit in the now-pytest repository). However, there were
|
||||
various discussions about features/ideas on the mailinglist, and `a
|
||||
couple of
|
||||
releases <https://pypi.org/project/py/0.8.0-alpha2/#history>`__ every
|
||||
couple of months:
|
||||
|
||||
- March 2006: py 0.8.0-alpha2
|
||||
- May 2007: py 0.9.0
|
||||
- March 2008: py 0.9.1 (first release to be found `in the pytest
|
||||
changelog <https://github.com/pytest-dev/pytest/blob/main/doc/en/changelog.rst#091>`__!)
|
||||
- August 2008: py 0.9.2
|
||||
|
||||
- In August 2009, py 1.0.0 was released, `introducing a lot of
|
||||
fundamental
|
||||
features <https://holgerkrekel.net/2009/08/04/pylib-1-0-0-released-the-testing-with-python-innovations-continue/>`__:
|
||||
|
||||
- funcargs/fixtures
|
||||
- A `plugin
|
||||
architecture <http://web.archive.org/web/20090629032718/https://codespeak.net/py/dist/test/extend.html>`__
|
||||
which still looks very much the same today!
|
||||
- Various `default
|
||||
plugins <http://web.archive.org/web/20091005181132/https://codespeak.net/py/dist/test/plugin/index.html>`__,
|
||||
including
|
||||
`monkeypatch <http://web.archive.org/web/20091012022829/http://codespeak.net/py/dist/test/plugin/monkeypatch.html>`__
|
||||
|
||||
- Even back there, the
|
||||
`FAQ <http://web.archive.org/web/20091005222413/http://codespeak.net/py/dist/faq.html>`__
|
||||
said:
|
||||
|
||||
Clearly, [a second standard library] was ambitious and the naming has
|
||||
maybe haunted the project rather than helping it. There may be a
|
||||
project name change and possibly a split up into different projects
|
||||
sometime.
|
||||
|
||||
and that finally happened in November 2010, when pytest 2.0.0 `was
|
||||
released <https://mail.python.org/pipermail/pytest-dev/2010-November/001687.html>`__
|
||||
as a package separate from ``py`` (but still called ``py.test``).
|
||||
|
||||
- In August 2016, pytest 3.0.0 `was
|
||||
released <https://docs.pytest.org/en/latest/changelog.html#id1313>`__,
|
||||
which adds ``pytest`` (rather than ``py.test``) as the recommended
|
||||
command-line entry point
|
||||
|
||||
Due to this history, it's diffcult to answer the question when pytest was started.
|
||||
It depends what point should really be seen as the start of it all. One
|
||||
possible interpretation is to pick Europython 2004, i.e. around June/July
|
||||
2004.
|
||||
@@ -1,162 +0,0 @@
|
||||
.. _how-to-handle-failures:
|
||||
|
||||
How to handle test failures
|
||||
=============================
|
||||
|
||||
.. _maxfail:
|
||||
|
||||
Stopping after the first (or N) failures
|
||||
---------------------------------------------------
|
||||
|
||||
To stop the testing process after the first (N) failures:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -x # stop after first failure
|
||||
pytest --maxfail=2 # stop after two failures
|
||||
|
||||
|
||||
.. _pdb-option:
|
||||
|
||||
Using PDB_ (Python Debugger) with pytest
|
||||
----------------------------------------------------------
|
||||
|
||||
Dropping to PDB_ (Python Debugger) on failures
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. _PDB: https://docs.python.org/library/pdb.html
|
||||
|
||||
Python comes with a builtin Python debugger called PDB_. ``pytest``
|
||||
allows one to drop into the PDB_ prompt via a command line option:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --pdb
|
||||
|
||||
This will invoke the Python debugger on every failure (or KeyboardInterrupt).
|
||||
Often you might only want to do this for the first failing test to understand
|
||||
a certain failure situation:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -x --pdb # drop to PDB on first failure, then end test session
|
||||
pytest --pdb --maxfail=3 # drop to PDB for first three failures
|
||||
|
||||
Note that on any failure the exception information is stored on
|
||||
``sys.last_value``, ``sys.last_type`` and ``sys.last_traceback``. In
|
||||
interactive use, this allows one to drop into postmortem debugging with
|
||||
any debug tool. One can also manually access the exception information,
|
||||
for example::
|
||||
|
||||
>>> import sys
|
||||
>>> sys.last_traceback.tb_lineno
|
||||
42
|
||||
>>> sys.last_value
|
||||
AssertionError('assert result == "ok"',)
|
||||
|
||||
|
||||
.. _trace-option:
|
||||
|
||||
Dropping to PDB_ at the start of a test
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``pytest`` allows one to drop into the PDB_ prompt immediately at the start of each test via a command line option:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --trace
|
||||
|
||||
This will invoke the Python debugger at the start of every test.
|
||||
|
||||
.. _breakpoints:
|
||||
|
||||
Setting breakpoints
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded: 2.4.0
|
||||
|
||||
To set a breakpoint in your code use the native Python ``import pdb;pdb.set_trace()`` call
|
||||
in your code and pytest automatically disables its output capture for that test:
|
||||
|
||||
* Output capture in other tests is not affected.
|
||||
* Any prior test output that has already been captured and will be processed as
|
||||
such.
|
||||
* Output capture gets resumed when ending the debugger session (via the
|
||||
``continue`` command).
|
||||
|
||||
|
||||
.. _`breakpoint-builtin`:
|
||||
|
||||
Using the builtin breakpoint function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Python 3.7 introduces a builtin ``breakpoint()`` function.
|
||||
Pytest supports the use of ``breakpoint()`` with the following behaviours:
|
||||
|
||||
- When ``breakpoint()`` is called and ``PYTHONBREAKPOINT`` is set to the default value, pytest will use the custom internal PDB trace UI instead of the system default ``Pdb``.
|
||||
- When tests are complete, the system will default back to the system ``Pdb`` trace UI.
|
||||
- With ``--pdb`` passed to pytest, the custom internal Pdb trace UI is used with both ``breakpoint()`` and failed tests/unhandled exceptions.
|
||||
- ``--pdbcls`` can be used to specify a custom debugger class.
|
||||
|
||||
|
||||
.. _faulthandler:
|
||||
|
||||
Fault Handler
|
||||
-------------
|
||||
|
||||
.. versionadded:: 5.0
|
||||
|
||||
The `faulthandler <https://docs.python.org/3/library/faulthandler.html>`__ standard module
|
||||
can be used to dump Python tracebacks on a segfault or after a timeout.
|
||||
|
||||
The module is automatically enabled for pytest runs, unless the ``-p no:faulthandler`` is given
|
||||
on the command-line.
|
||||
|
||||
Also the :confval:`faulthandler_timeout=X<faulthandler_timeout>` configuration option can be used
|
||||
to dump the traceback of all threads if a test takes longer than ``X``
|
||||
seconds to finish (not available on Windows).
|
||||
|
||||
.. note::
|
||||
|
||||
This functionality has been integrated from the external
|
||||
`pytest-faulthandler <https://github.com/pytest-dev/pytest-faulthandler>`__ plugin, with two
|
||||
small differences:
|
||||
|
||||
* To disable it, use ``-p no:faulthandler`` instead of ``--no-faulthandler``: the former
|
||||
can be used with any plugin, so it saves one option.
|
||||
|
||||
* The ``--faulthandler-timeout`` command-line option has become the
|
||||
:confval:`faulthandler_timeout` configuration option. It can still be configured from
|
||||
the command-line using ``-o faulthandler_timeout=X``.
|
||||
|
||||
|
||||
.. _unraisable:
|
||||
|
||||
Warning about unraisable exceptions and unhandled thread exceptions
|
||||
-------------------------------------------------------------------
|
||||
|
||||
.. versionadded:: 6.2
|
||||
|
||||
.. note::
|
||||
|
||||
These features only work on Python>=3.8.
|
||||
|
||||
Unhandled exceptions are exceptions that are raised in a situation in which
|
||||
they cannot propagate to a caller. The most common case is an exception raised
|
||||
in a :meth:`__del__ <object.__del__>` implementation.
|
||||
|
||||
Unhandled thread exceptions are exceptions raised in a :class:`~threading.Thread`
|
||||
but not handled, causing the thread to terminate uncleanly.
|
||||
|
||||
Both types of exceptions are normally considered bugs, but may go unnoticed
|
||||
because they don't cause the program itself to crash. Pytest detects these
|
||||
conditions and issues a warning that is visible in the test run summary.
|
||||
|
||||
The plugins are automatically enabled for pytest runs, unless the
|
||||
``-p no:unraisableexception`` (for unraisable exceptions) and
|
||||
``-p no:threadexception`` (for thread exceptions) options are given on the
|
||||
command-line.
|
||||
|
||||
The warnings may be silenced selectively using the :ref:`pytest.mark.filterwarnings ref`
|
||||
mark. The warning categories are :class:`pytest.PytestUnraisableExceptionWarning` and
|
||||
:class:`pytest.PytestUnhandledThreadExceptionWarning`.
|
||||
@@ -1,64 +0,0 @@
|
||||
:orphan:
|
||||
|
||||
.. _how-to:
|
||||
|
||||
How-to guides
|
||||
================
|
||||
|
||||
Core pytest functionality
|
||||
-------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
usage
|
||||
assert
|
||||
fixtures
|
||||
mark
|
||||
parametrize
|
||||
tmpdir
|
||||
monkeypatch
|
||||
doctest
|
||||
cache
|
||||
|
||||
Test output and outcomes
|
||||
----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
failures
|
||||
output
|
||||
logging
|
||||
capture-stdout-stderr
|
||||
capture-warnings
|
||||
skipping
|
||||
|
||||
Plugins
|
||||
----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
plugins
|
||||
writing_plugins
|
||||
writing_hook_functions
|
||||
|
||||
pytest and other test systems
|
||||
-----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
existingtestsuite
|
||||
unittest
|
||||
nose
|
||||
xunit_setup
|
||||
|
||||
pytest development environment
|
||||
------------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
bash-completion
|
||||
@@ -1,233 +0,0 @@
|
||||
|
||||
.. _usage:
|
||||
|
||||
How to invoke pytest
|
||||
==========================================
|
||||
|
||||
.. seealso:: :ref:`Complete pytest command-line flag reference <command-line-flags>`
|
||||
|
||||
In general, pytest is invoked with the command ``pytest`` (see below for :ref:`other ways to invoke pytest
|
||||
<invoke-other>`). This will execute all tests in all files whose names follow the form ``test_*.py`` or ``\*_test.py``
|
||||
in the current directory and its subdirectories. More generally, pytest follows :ref:`standard test discovery rules
|
||||
<test discovery>`.
|
||||
|
||||
|
||||
.. _select-tests:
|
||||
|
||||
Specifying which tests to run
|
||||
------------------------------
|
||||
|
||||
Pytest supports several ways to run and select tests from the command-line.
|
||||
|
||||
**Run tests in a module**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest test_mod.py
|
||||
|
||||
**Run tests in a directory**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest testing/
|
||||
|
||||
**Run tests by keyword expressions**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -k "MyClass and not method"
|
||||
|
||||
This will run tests which contain names that match the given *string expression* (case-insensitive),
|
||||
which can include Python operators that use filenames, class names and function names as variables.
|
||||
The example above will run ``TestMyClass.test_something`` but not ``TestMyClass.test_method_simple``.
|
||||
|
||||
.. _nodeids:
|
||||
|
||||
**Run tests by node ids**
|
||||
|
||||
Each collected test is assigned a unique ``nodeid`` which consist of the module filename followed
|
||||
by specifiers like class names, function names and parameters from parametrization, separated by ``::`` characters.
|
||||
|
||||
To run a specific test within a module:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest test_mod.py::test_func
|
||||
|
||||
|
||||
Another example specifying a test method in the command line:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest test_mod.py::TestClass::test_method
|
||||
|
||||
**Run tests by marker expressions**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -m slow
|
||||
|
||||
Will run all tests which are decorated with the ``@pytest.mark.slow`` decorator.
|
||||
|
||||
For more information see :ref:`marks <mark>`.
|
||||
|
||||
**Run tests from packages**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --pyargs pkg.testing
|
||||
|
||||
This will import ``pkg.testing`` and use its filesystem location to find and run tests from.
|
||||
|
||||
|
||||
Getting help on version, option names, environment variables
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --version # shows where pytest was imported from
|
||||
pytest --fixtures # show available builtin function arguments
|
||||
pytest -h | --help # show help on command line and config file options
|
||||
|
||||
|
||||
.. _durations:
|
||||
|
||||
Profiling test execution duration
|
||||
-------------------------------------
|
||||
|
||||
.. versionchanged:: 6.0
|
||||
|
||||
To get a list of the slowest 10 test durations over 1.0s long:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --durations=10 --durations-min=1.0
|
||||
|
||||
By default, pytest will not show test durations that are too small (<0.005s) unless ``-vv`` is passed on the command-line.
|
||||
|
||||
|
||||
Managing loading of plugins
|
||||
-------------------------------
|
||||
|
||||
Early loading plugins
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can early-load plugins (internal and external) explicitly in the command-line with the ``-p`` option::
|
||||
|
||||
pytest -p mypluginmodule
|
||||
|
||||
The option receives a ``name`` parameter, which can be:
|
||||
|
||||
* A full module dotted name, for example ``myproject.plugins``. This dotted name must be importable.
|
||||
* The entry-point name of a plugin. This is the name passed to ``setuptools`` when the plugin is
|
||||
registered. For example to early-load the `pytest-cov <https://pypi.org/project/pytest-cov/>`__ plugin you can use::
|
||||
|
||||
pytest -p pytest_cov
|
||||
|
||||
|
||||
Disabling plugins
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To disable loading specific plugins at invocation time, use the ``-p`` option
|
||||
together with the prefix ``no:``.
|
||||
|
||||
Example: to disable loading the plugin ``doctest``, which is responsible for
|
||||
executing doctest tests from text files, invoke pytest like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -p no:doctest
|
||||
|
||||
|
||||
.. _invoke-other:
|
||||
|
||||
Other ways of calling pytest
|
||||
-----------------------------------------------------
|
||||
|
||||
.. _invoke-python:
|
||||
|
||||
Calling pytest through ``python -m pytest``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can invoke testing through the Python interpreter from the command line:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
python -m pytest [...]
|
||||
|
||||
This is almost equivalent to invoking the command line script ``pytest [...]``
|
||||
directly, except that calling via ``python`` will also add the current directory to ``sys.path``.
|
||||
|
||||
|
||||
.. _`pytest.main-usage`:
|
||||
|
||||
Calling pytest from Python code
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can invoke ``pytest`` from Python code directly:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
retcode = pytest.main()
|
||||
|
||||
this acts as if you would call "pytest" from the command line.
|
||||
It will not raise :class:`SystemExit` but return the :ref:`exit code <exit-codes>` instead.
|
||||
You can pass in options and arguments:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
retcode = pytest.main(["-x", "mytestdir"])
|
||||
|
||||
You can specify additional plugins to ``pytest.main``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of myinvoke.py
|
||||
import pytest
|
||||
|
||||
|
||||
class MyPlugin:
|
||||
def pytest_sessionfinish(self):
|
||||
print("*** test run reporting finishing")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main(["-qq"], plugins=[MyPlugin()]))
|
||||
|
||||
Running it will show that ``MyPlugin`` was added and its
|
||||
hook was invoked:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ python myinvoke.py
|
||||
.FEsxX. [100%]*** test run reporting finishing
|
||||
|
||||
================================== ERRORS ==================================
|
||||
_______________________ ERROR at setup of test_error _______________________
|
||||
|
||||
@pytest.fixture
|
||||
def error_fixture():
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
test_example.py:6: AssertionError
|
||||
================================= FAILURES =================================
|
||||
________________________________ test_fail _________________________________
|
||||
|
||||
def test_fail():
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
test_example.py:14: AssertionError
|
||||
========================= short test summary info ==========================
|
||||
FAILED test_example.py::test_fail - assert 0
|
||||
ERROR test_example.py::test_error - assert 0
|
||||
|
||||
.. note::
|
||||
|
||||
Calling ``pytest.main()`` will result in importing your tests and any modules
|
||||
that they import. Due to the caching mechanism of python's import system,
|
||||
making subsequent calls to ``pytest.main()`` from the same process will not
|
||||
reflect changes to those files between the calls. For this reason, making
|
||||
multiple calls to ``pytest.main()`` from the same process (in order to re-run
|
||||
tests, for example) is not recommended.
|
||||
@@ -1,313 +0,0 @@
|
||||
.. _`writinghooks`:
|
||||
|
||||
Writing hook functions
|
||||
======================
|
||||
|
||||
|
||||
.. _validation:
|
||||
|
||||
hook function validation and execution
|
||||
--------------------------------------
|
||||
|
||||
pytest calls hook functions from registered plugins for any
|
||||
given hook specification. Let's look at a typical hook function
|
||||
for the ``pytest_collection_modifyitems(session, config,
|
||||
items)`` hook which pytest calls after collection of all test items is
|
||||
completed.
|
||||
|
||||
When we implement a ``pytest_collection_modifyitems`` function in our plugin
|
||||
pytest will during registration verify that you use argument
|
||||
names which match the specification and bail out if not.
|
||||
|
||||
Let's look at a possible implementation:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_collection_modifyitems(config, items):
|
||||
# called after collection is completed
|
||||
# you can modify the ``items`` list
|
||||
...
|
||||
|
||||
Here, ``pytest`` will pass in ``config`` (the pytest config object)
|
||||
and ``items`` (the list of collected test items) but will not pass
|
||||
in the ``session`` argument because we didn't list it in the function
|
||||
signature. This dynamic "pruning" of arguments allows ``pytest`` to
|
||||
be "future-compatible": we can introduce new hook named parameters without
|
||||
breaking the signatures of existing hook implementations. It is one of
|
||||
the reasons for the general long-lived compatibility of pytest plugins.
|
||||
|
||||
Note that hook functions other than ``pytest_runtest_*`` are not
|
||||
allowed to raise exceptions. Doing so will break the pytest run.
|
||||
|
||||
|
||||
|
||||
.. _firstresult:
|
||||
|
||||
firstresult: stop at first non-None result
|
||||
-------------------------------------------
|
||||
|
||||
Most calls to ``pytest`` hooks result in a **list of results** which contains
|
||||
all non-None results of the called hook functions.
|
||||
|
||||
Some hook specifications use the ``firstresult=True`` option so that the hook
|
||||
call only executes until the first of N registered functions returns a
|
||||
non-None result which is then taken as result of the overall hook call.
|
||||
The remaining hook functions will not be called in this case.
|
||||
|
||||
.. _`hookwrapper`:
|
||||
|
||||
hookwrapper: executing around other hooks
|
||||
-------------------------------------------------
|
||||
|
||||
.. currentmodule:: _pytest.core
|
||||
|
||||
|
||||
|
||||
pytest plugins can implement hook wrappers which wrap the execution
|
||||
of other hook implementations. A hook wrapper is a generator function
|
||||
which yields exactly once. When pytest invokes hooks it first executes
|
||||
hook wrappers and passes the same arguments as to the regular hooks.
|
||||
|
||||
At the yield point of the hook wrapper pytest will execute the next hook
|
||||
implementations and return their result to the yield point in the form of
|
||||
a :py:class:`Result <pluggy._Result>` instance which encapsulates a result or
|
||||
exception info. The yield point itself will thus typically not raise
|
||||
exceptions (unless there are bugs).
|
||||
|
||||
Here is an example definition of a hook wrapper:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_pyfunc_call(pyfuncitem):
|
||||
do_something_before_next_hook_executes()
|
||||
|
||||
outcome = yield
|
||||
# outcome.excinfo may be None or a (cls, val, tb) tuple
|
||||
|
||||
res = outcome.get_result() # will raise if outcome was exception
|
||||
|
||||
post_process_result(res)
|
||||
|
||||
outcome.force_result(new_res) # to override the return value to the plugin system
|
||||
|
||||
Note that hook wrappers don't return results themselves, they merely
|
||||
perform tracing or other side effects around the actual hook implementations.
|
||||
If the result of the underlying hook is a mutable object, they may modify
|
||||
that result but it's probably better to avoid it.
|
||||
|
||||
For more information, consult the
|
||||
:ref:`pluggy documentation about hookwrappers <pluggy:hookwrappers>`.
|
||||
|
||||
.. _plugin-hookorder:
|
||||
|
||||
Hook function ordering / call example
|
||||
-------------------------------------
|
||||
|
||||
For any given hook specification there may be more than one
|
||||
implementation and we thus generally view ``hook`` execution as a
|
||||
``1:N`` function call where ``N`` is the number of registered functions.
|
||||
There are ways to influence if a hook implementation comes before or
|
||||
after others, i.e. the position in the ``N``-sized list of functions:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Plugin 1
|
||||
@pytest.hookimpl(tryfirst=True)
|
||||
def pytest_collection_modifyitems(items):
|
||||
# will execute as early as possible
|
||||
...
|
||||
|
||||
|
||||
# Plugin 2
|
||||
@pytest.hookimpl(trylast=True)
|
||||
def pytest_collection_modifyitems(items):
|
||||
# will execute as late as possible
|
||||
...
|
||||
|
||||
|
||||
# Plugin 3
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_collection_modifyitems(items):
|
||||
# will execute even before the tryfirst one above!
|
||||
outcome = yield
|
||||
# will execute after all non-hookwrappers executed
|
||||
|
||||
Here is the order of execution:
|
||||
|
||||
1. Plugin3's pytest_collection_modifyitems called until the yield point
|
||||
because it is a hook wrapper.
|
||||
|
||||
2. Plugin1's pytest_collection_modifyitems is called because it is marked
|
||||
with ``tryfirst=True``.
|
||||
|
||||
3. Plugin2's pytest_collection_modifyitems is called because it is marked
|
||||
with ``trylast=True`` (but even without this mark it would come after
|
||||
Plugin1).
|
||||
|
||||
4. Plugin3's pytest_collection_modifyitems then executing the code after the yield
|
||||
point. The yield receives a :py:class:`Result <pluggy._Result>` instance which encapsulates
|
||||
the result from calling the non-wrappers. Wrappers shall not modify the result.
|
||||
|
||||
It's possible to use ``tryfirst`` and ``trylast`` also in conjunction with
|
||||
``hookwrapper=True`` in which case it will influence the ordering of hookwrappers
|
||||
among each other.
|
||||
|
||||
|
||||
Declaring new hooks
|
||||
------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
This is a quick overview on how to add new hooks and how they work in general, but a more complete
|
||||
overview can be found in `the pluggy documentation <https://pluggy.readthedocs.io/en/latest/>`__.
|
||||
|
||||
.. currentmodule:: _pytest.hookspec
|
||||
|
||||
Plugins and ``conftest.py`` files may declare new hooks that can then be
|
||||
implemented by other plugins in order to alter behaviour or interact with
|
||||
the new plugin:
|
||||
|
||||
.. autofunction:: pytest_addhooks
|
||||
:noindex:
|
||||
|
||||
Hooks are usually declared as do-nothing functions that contain only
|
||||
documentation describing when the hook will be called and what return values
|
||||
are expected. The names of the functions must start with `pytest_` otherwise pytest won't recognize them.
|
||||
|
||||
Here's an example. Let's assume this code is in the ``sample_hook.py`` module.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_my_hook(config):
|
||||
"""
|
||||
Receives the pytest config and does things with it
|
||||
"""
|
||||
|
||||
To register the hooks with pytest they need to be structured in their own module or class. This
|
||||
class or module can then be passed to the ``pluginmanager`` using the ``pytest_addhooks`` function
|
||||
(which itself is a hook exposed by pytest).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_addhooks(pluginmanager):
|
||||
""" This example assumes the hooks are grouped in the 'sample_hook' module. """
|
||||
from my_app.tests import sample_hook
|
||||
|
||||
pluginmanager.add_hookspecs(sample_hook)
|
||||
|
||||
For a real world example, see `newhooks.py`_ from `xdist <https://github.com/pytest-dev/pytest-xdist>`_.
|
||||
|
||||
.. _`newhooks.py`: https://github.com/pytest-dev/pytest-xdist/blob/974bd566c599dc6a9ea291838c6f226197208b46/xdist/newhooks.py
|
||||
|
||||
Hooks may be called both from fixtures or from other hooks. In both cases, hooks are called
|
||||
through the ``hook`` object, available in the ``config`` object. Most hooks receive a
|
||||
``config`` object directly, while fixtures may use the ``pytestconfig`` fixture which provides the same object.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(pytestconfig):
|
||||
# call the hook called "pytest_my_hook"
|
||||
# 'result' will be a list of return values from all registered functions.
|
||||
result = pytestconfig.hook.pytest_my_hook(config=pytestconfig)
|
||||
|
||||
.. note::
|
||||
Hooks receive parameters using only keyword arguments.
|
||||
|
||||
Now your hook is ready to be used. To register a function at the hook, other plugins or users must
|
||||
now simply define the function ``pytest_my_hook`` with the correct signature in their ``conftest.py``.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_my_hook(config):
|
||||
"""
|
||||
Print all active hooks to the screen.
|
||||
"""
|
||||
print(config.hook)
|
||||
|
||||
|
||||
.. _`addoptionhooks`:
|
||||
|
||||
|
||||
Using hooks in pytest_addoption
|
||||
-------------------------------
|
||||
|
||||
Occasionally, it is necessary to change the way in which command line options
|
||||
are defined by one plugin based on hooks in another plugin. For example,
|
||||
a plugin may expose a command line option for which another plugin needs
|
||||
to define the default value. The pluginmanager can be used to install and
|
||||
use hooks to accomplish this. The plugin would define and add the hooks
|
||||
and use pytest_addoption as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# contents of hooks.py
|
||||
|
||||
# Use firstresult=True because we only want one plugin to define this
|
||||
# default value
|
||||
@hookspec(firstresult=True)
|
||||
def pytest_config_file_default_value():
|
||||
""" Return the default value for the config file command line option. """
|
||||
|
||||
|
||||
# contents of myplugin.py
|
||||
|
||||
|
||||
def pytest_addhooks(pluginmanager):
|
||||
""" This example assumes the hooks are grouped in the 'hooks' module. """
|
||||
from . import hook
|
||||
|
||||
pluginmanager.add_hookspecs(hook)
|
||||
|
||||
|
||||
def pytest_addoption(parser, pluginmanager):
|
||||
default_value = pluginmanager.hook.pytest_config_file_default_value()
|
||||
parser.addoption(
|
||||
"--config-file",
|
||||
help="Config file to use, defaults to %(default)s",
|
||||
default=default_value,
|
||||
)
|
||||
|
||||
The conftest.py that is using myplugin would simply define the hook as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_config_file_default_value():
|
||||
return "config.yaml"
|
||||
|
||||
|
||||
Optionally using hooks from 3rd party plugins
|
||||
---------------------------------------------
|
||||
|
||||
Using new hooks from plugins as explained above might be a little tricky
|
||||
because of the standard :ref:`validation mechanism <validation>`:
|
||||
if you depend on a plugin that is not installed, validation will fail and
|
||||
the error message will not make much sense to your users.
|
||||
|
||||
One approach is to defer the hook implementation to a new plugin instead of
|
||||
declaring the hook functions directly in your plugin module, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# contents of myplugin.py
|
||||
|
||||
|
||||
class DeferPlugin:
|
||||
"""Simple plugin to defer pytest-xdist hook functions."""
|
||||
|
||||
def pytest_testnodedown(self, node, error):
|
||||
"""standard xdist hook function."""
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
if config.pluginmanager.hasplugin("xdist"):
|
||||
config.pluginmanager.register(DeferPlugin())
|
||||
|
||||
This has the added benefit of allowing you to conditionally install hooks
|
||||
depending on which plugins are installed.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="1500" height="1500" viewBox="0, 0, 1500, 1500">
|
||||
<g id="pytest_logo">
|
||||
<g id="graphics">
|
||||
<path d="M521.576,213.75 L952.616,213.75 C964.283,213.75 973.741,223.208 973.741,234.875 L973.741,234.875 C973.741,246.542 964.283,256 952.616,256 L521.576,256 C509.909,256 500.451,246.542 500.451,234.875 L500.451,234.875 C500.451,223.208 509.909,213.75 521.576,213.75 z" fill="#696969" id="horizontal_bar"/>
|
||||
<g id="top_bars">
|
||||
<path d="M525.333,171 L612,171 L612,191 L525.333,191 L525.333,171 z" fill="#009FE3"/>
|
||||
<path d="M638.667,171 L725.333,171 L725.333,191 L638.667,191 L638.667,171 z" fill="#C7D302"/>
|
||||
<path d="M750.5,171 L837.167,171 L837.167,191 L750.5,191 L750.5,171 z" fill="#F07E16"/>
|
||||
<path d="M861.861,171 L948.528,171 L948.528,191 L861.861,191 L861.861,171 z" fill="#DF2815"/>
|
||||
</g>
|
||||
<g id="bottom_bars">
|
||||
<path d="M861.861,278 L948.528,278 L948.528,424.5 L861.861,424.5 L861.861,278 z" fill="#DF2815"/>
|
||||
<path d="M750.5,278 L837.328,278 L837.328,516 L750.5,516 L750.5,278 z" fill="#F07E16"/>
|
||||
<path d="M638.667,278 L725.328,278 L725.328,634.5 L638.667,634.5 L638.667,278 z" fill="#C7D302"/>
|
||||
<path d="M525.333,278 L612,278 L612,712.5 L525.333,712.5 L525.333,278 z" fill="#009FE3"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="pytest">
|
||||
<path d="M252.959,1173.846 Q240.139,1173.846 229.71,1171.021 Q219.28,1168.196 210.914,1163.525 Q202.549,1158.853 196.139,1152.552 Q189.729,1146.25 184.732,1139.297 L182.124,1139.297 Q182.776,1146.685 183.428,1153.421 Q183.862,1159.07 184.297,1165.046 Q184.732,1171.021 184.732,1174.498 L184.732,1276.404 L145.186,1276.404 L145.186,930.921 L177.344,930.921 L182.993,963.079 L184.732,963.079 Q189.729,955.474 196.03,948.847 Q202.332,942.22 210.697,937.331 Q219.063,932.442 229.492,929.509 Q239.922,926.575 252.959,926.575 Q273.384,926.575 290.115,934.397 Q306.846,942.22 318.688,957.756 Q330.53,973.292 337.048,996.324 Q343.567,1019.356 343.567,1049.776 Q343.567,1080.413 337.048,1103.554 Q330.53,1126.695 318.688,1142.339 Q306.846,1157.984 290.115,1165.915 Q273.384,1173.846 252.959,1173.846 z M245.354,959.385 Q228.84,959.385 217.433,964.383 Q206.025,969.38 198.964,979.593 Q191.902,989.805 188.534,1005.015 Q185.166,1020.225 184.732,1040.867 L184.732,1049.776 Q184.732,1071.722 187.665,1088.779 Q190.598,1105.835 197.66,1117.46 Q204.722,1129.085 216.455,1135.06 Q228.189,1141.036 245.789,1141.036 Q275.122,1141.036 288.92,1117.352 Q302.717,1093.667 302.717,1049.341 Q302.717,1004.146 288.92,981.766 Q275.122,959.385 245.354,959.385 z" fill="#696969"/>
|
||||
<path d="M370.293,930.921 L411.36,930.921 L458.076,1064.117 Q461.118,1072.808 464.269,1082.369 Q467.42,1091.929 470.136,1101.49 Q472.852,1111.05 474.807,1119.959 Q476.763,1128.868 477.632,1136.473 L478.936,1136.473 Q480.022,1131.041 482.412,1121.697 Q484.802,1112.354 487.736,1101.816 Q490.669,1091.277 493.82,1081.065 Q496.97,1070.853 499.36,1063.682 L542.6,930.921 L583.45,930.921 L489.148,1200.572 Q483.064,1218.172 476.002,1232.187 Q468.941,1246.202 459.597,1255.979 Q450.254,1265.757 437.651,1271.081 Q425.049,1276.404 407.666,1276.404 Q396.367,1276.404 388.11,1275.209 Q379.854,1274.014 373.987,1272.71 L373.987,1241.204 Q378.55,1242.291 385.503,1243.051 Q392.456,1243.812 400.061,1243.812 Q410.491,1243.812 418.096,1241.313 Q425.701,1238.814 431.35,1234.034 Q437,1229.253 441.019,1222.3 Q445.039,1215.347 448.298,1206.438 L460.684,1171.673 z" fill="#696969"/>
|
||||
<path d="M695.568,1141.47 Q699.479,1141.47 704.368,1141.036 Q709.257,1140.601 713.82,1139.949 Q718.383,1139.297 722.186,1138.428 Q725.988,1137.559 727.944,1136.907 L727.944,1166.893 Q725.119,1168.196 720.773,1169.5 Q716.428,1170.804 711.213,1171.781 Q705.998,1172.759 700.349,1173.302 Q694.699,1173.846 689.267,1173.846 Q675.795,1173.846 664.279,1170.369 Q652.763,1166.893 644.398,1158.418 Q636.032,1149.944 631.252,1135.495 Q626.472,1121.045 626.472,1099.1 L626.472,960.689 L592.792,960.689 L592.792,943.089 L626.472,926.141 L643.42,876.165 L666.235,876.165 L666.235,930.921 L726.206,930.921 L726.206,960.689 L666.235,960.689 L666.235,1099.1 Q666.235,1120.176 673.079,1130.823 Q679.924,1141.47 695.568,1141.47 z" fill="#009FE3"/>
|
||||
<path d="M868.527,1173.846 Q844.626,1173.846 824.853,1165.806 Q805.08,1157.767 790.848,1142.339 Q776.616,1126.912 768.793,1104.097 Q760.971,1081.282 760.971,1051.949 Q760.971,1022.398 768.142,999.148 Q775.312,975.899 788.349,959.711 Q801.386,943.523 819.529,935.049 Q837.673,926.575 859.619,926.575 Q881.13,926.575 898.295,934.289 Q915.461,942.002 927.412,956.017 Q939.362,970.032 945.772,989.697 Q952.182,1009.361 952.182,1033.262 L952.182,1057.815 L801.821,1057.815 Q802.907,1099.751 819.529,1119.524 Q836.152,1139.297 868.962,1139.297 Q880.043,1139.297 889.495,1138.211 Q898.947,1137.125 907.747,1135.06 Q916.547,1132.996 924.804,1129.845 Q933.061,1126.695 941.535,1122.784 L941.535,1157.984 Q932.844,1162.112 924.478,1165.154 Q916.113,1168.196 907.313,1170.152 Q898.513,1172.107 889.061,1172.977 Q879.609,1173.846 868.527,1173.846 z M858.749,959.385 Q833.979,959.385 819.529,976.333 Q805.08,993.282 802.69,1025.657 L909.594,1025.657 Q909.594,1010.882 906.661,998.605 Q903.727,986.329 897.535,977.637 Q891.342,968.946 881.782,964.166 Q872.221,959.385 858.749,959.385 z" fill="#009FE3"/>
|
||||
<path d="M1155.126,1104.097 Q1155.126,1121.48 1148.825,1134.517 Q1142.524,1147.554 1130.682,1156.354 Q1118.84,1165.154 1102.109,1169.5 Q1085.378,1173.846 1064.518,1173.846 Q1040.834,1173.846 1023.886,1170.043 Q1006.938,1166.241 994.118,1158.853 L994.118,1122.784 Q1000.854,1126.26 1009.111,1129.628 Q1017.368,1132.996 1026.494,1135.604 Q1035.62,1138.211 1045.289,1139.841 Q1054.958,1141.47 1064.518,1141.47 Q1078.642,1141.47 1088.528,1139.08 Q1098.415,1136.69 1104.608,1132.236 Q1110.8,1127.781 1113.625,1121.371 Q1116.45,1114.961 1116.45,1107.139 Q1116.45,1100.403 1114.277,1094.971 Q1112.104,1089.539 1106.346,1084.216 Q1100.588,1078.892 1090.593,1073.46 Q1080.598,1068.028 1064.953,1061.292 Q1049.308,1054.556 1036.815,1048.038 Q1024.321,1041.519 1015.629,1033.479 Q1006.938,1025.44 1002.266,1014.902 Q997.595,1004.363 997.595,989.805 Q997.595,974.595 1003.57,962.753 Q1009.545,950.911 1020.41,942.872 Q1031.274,934.832 1046.484,930.704 Q1061.694,926.575 1080.38,926.575 Q1101.457,926.575 1118.948,931.138 Q1136.44,935.701 1152.084,943.089 L1138.395,975.03 Q1124.272,968.729 1109.388,964.057 Q1094.504,959.385 1079.077,959.385 Q1056.913,959.385 1046.266,966.664 Q1035.62,973.943 1035.62,987.415 Q1035.62,995.02 1038.118,1000.669 Q1040.617,1006.319 1046.701,1011.316 Q1052.785,1016.314 1062.997,1021.42 Q1073.21,1026.526 1088.42,1032.828 Q1104.064,1039.346 1116.341,1045.865 Q1128.618,1052.383 1137.309,1060.531 Q1146,1068.68 1150.563,1079.109 Q1155.126,1089.539 1155.126,1104.097 z" fill="#009FE3"/>
|
||||
<path d="M1285.28,1141.47 Q1289.191,1141.47 1294.08,1141.036 Q1298.969,1140.601 1303.532,1139.949 Q1308.095,1139.297 1311.898,1138.428 Q1315.7,1137.559 1317.656,1136.907 L1317.656,1166.893 Q1314.831,1168.196 1310.485,1169.5 Q1306.14,1170.804 1300.925,1171.781 Q1295.71,1172.759 1290.06,1173.302 Q1284.411,1173.846 1278.979,1173.846 Q1265.507,1173.846 1253.991,1170.369 Q1242.475,1166.893 1234.109,1158.418 Q1225.744,1149.944 1220.964,1135.495 Q1216.183,1121.045 1216.183,1099.1 L1216.183,960.689 L1182.504,960.689 L1182.504,943.089 L1216.183,926.141 L1233.132,876.165 L1255.947,876.165 L1255.947,930.921 L1315.917,930.921 L1315.917,960.689 L1255.947,960.689 L1255.947,1099.1 Q1255.947,1120.176 1262.791,1130.823 Q1269.636,1141.47 1285.28,1141.47 z" fill="#009FE3"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -2,9 +2,8 @@
|
||||
|
||||
.. sidebar:: Next Open Trainings
|
||||
|
||||
- `Introduction to pytest <https://ep2021.europython.eu/talks/7S5Cnc6-introduction-to-pytest/>`_, part of `Europython 2021 <https://ep2021.europython.eu/>`_, July 27th, remote.
|
||||
- `pytest: Professionelles Testen (nicht nur) für Python <https://workshoptage.ch/workshops/2021/pytest-test-driven-development-nicht-nur-fuer-python-2/>`_ (German), part of `CH-Open Workshoptage <https://workshoptage.ch/>`_, September 9th, ETH Zurich, Switzerland.
|
||||
- `Professional Testing with Python <https://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, via `Python Academy <https://www.python-academy.com/>`_, Q4/2021 (TBD, 3 days), Leipzig (Germany) and remote.
|
||||
- `Professional Testing with Python <https://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, via `Python Academy <https://www.python-academy.com/>`_, February 1st to 3rd, 2022, Leipzig (Germany) and remote.
|
||||
|
||||
Also see `previous talks and blogposts <talks.html>`_.
|
||||
|
||||
@@ -15,19 +14,10 @@ pytest: helps you write better programs
|
||||
|
||||
.. module:: pytest
|
||||
|
||||
The ``pytest`` framework makes it easy to write small, readable tests, and can
|
||||
scale to support complex functional testing for applications and libraries.
|
||||
The ``pytest`` framework makes it easy to write small tests, yet
|
||||
scales to support complex functional testing for applications and libraries.
|
||||
|
||||
|
||||
**Pythons**: ``pytest`` requires: Python 3.6, 3.7, 3.8, 3.9, or PyPy3.
|
||||
|
||||
**PyPI package name**: `pytest <https://pypi.org/project/pytest/>`_
|
||||
|
||||
**Documentation as PDF**: `download latest <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_
|
||||
|
||||
|
||||
A quick example
|
||||
---------------
|
||||
An example of a simple test:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -46,7 +36,7 @@ To execute it:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -67,7 +57,7 @@ To execute it:
|
||||
============================ 1 failed in 0.12s =============================
|
||||
|
||||
Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used.
|
||||
See :ref:`Get started <getstarted>` for a basic introduction to using pytest.
|
||||
See :ref:`Getting Started <getstarted>` for more examples.
|
||||
|
||||
|
||||
Features
|
||||
@@ -83,16 +73,13 @@ Features
|
||||
|
||||
- Python 3.6+ and PyPy 3
|
||||
|
||||
- Rich plugin architecture, with over 800+ :ref:`external plugins <plugin-list>` and thriving community
|
||||
- Rich plugin architecture, with over 315+ `external plugins <https://docs.pytest.org/en/latest/reference/plugin_list.html>`_ and thriving community
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* :ref:`Get started <get-started>` - install pytest and grasp its basics just twenty minutes
|
||||
* :ref:`How-to guides <how-to>` - step-by-step guides, covering a vast range of use-cases and needs
|
||||
* :ref:`Reference guides <reference>` - includes the complete pytest API reference, lists of plugins and more
|
||||
* :ref:`Explanation <explanation>` - background, discussion of key topics, answers to higher-level questions
|
||||
Please see :ref:`Contents <toc>` for full documentation, including installation, tutorials and PDF documents.
|
||||
|
||||
|
||||
Bugs/Requests
|
||||
@@ -133,7 +120,7 @@ Save time, reduce risk, and improve code health, while paying the maintainers of
|
||||
`Learn more. <https://tidelift.com/subscription/pkg/pypi-pytest?utm_source=pypi-pytest&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`_
|
||||
|
||||
Security
|
||||
~~~~~~~~
|
||||
^^^^^^^^
|
||||
|
||||
pytest has never been associated with a security vulnerability, but in any case, to report a
|
||||
security vulnerability please use the `Tidelift security contact <https://tidelift.com/security>`_.
|
||||
|
||||
@@ -9,7 +9,7 @@ Distributed under the terms of the `MIT`_ license, pytest is free and open sourc
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2004-2021 Holger Krekel and others
|
||||
Copyright (c) 2004-2020 Holger Krekel and others
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
.. _logging:
|
||||
|
||||
How to manage logging
|
||||
---------------------
|
||||
Logging
|
||||
-------
|
||||
|
||||
|
||||
|
||||
|
||||
pytest captures log messages of level ``WARNING`` or above automatically and displays them in their own section
|
||||
for each failed test in the same manner as captured stdout and stderr.
|
||||
@@ -167,7 +170,7 @@ the records for the ``setup`` and ``call`` stages during teardown like so:
|
||||
|
||||
|
||||
|
||||
The full API is available at :class:`pytest.LogCaptureFixture`.
|
||||
The full API is available at :class:`_pytest.logging.LogCaptureFixture`.
|
||||
|
||||
|
||||
.. _live_logs:
|
||||
@@ -1,7 +1,7 @@
|
||||
.. _mark:
|
||||
|
||||
How to mark test functions with attributes
|
||||
===========================================
|
||||
Marking test functions with attributes
|
||||
======================================
|
||||
|
||||
By using the ``pytest.mark`` helper you can easily set
|
||||
metadata on your test functions. You can find the full list of builtin markers
|
||||
@@ -1,6 +1,5 @@
|
||||
.. _monkeypatching:
|
||||
|
||||
How to monkeypatch/mock modules and environments
|
||||
Monkeypatching/mocking modules and environments
|
||||
================================================================
|
||||
|
||||
.. currentmodule:: _pytest.monkeypatch
|
||||
@@ -17,7 +16,6 @@ functionality in tests:
|
||||
.. code-block:: python
|
||||
|
||||
monkeypatch.setattr(obj, name, value, raising=True)
|
||||
monkeypatch.setattr("somemodule.obj.name", value, raising=True)
|
||||
monkeypatch.delattr(obj, name, raising=True)
|
||||
monkeypatch.setitem(mapping, name, value)
|
||||
monkeypatch.delitem(obj, name, raising=True)
|
||||
@@ -58,7 +56,7 @@ call ``pkg_resources.fixup_namespace_packages`` and :py:func:`importlib.invalida
|
||||
See the `monkeypatch blog post`_ for some introduction material
|
||||
and a discussion of its motivation.
|
||||
|
||||
.. _`monkeypatch blog post`: https://tetamap.wordpress.com//2009/03/03/monkeypatching-in-unit-tests-done-right/
|
||||
.. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
|
||||
|
||||
Simple example: monkeypatching functions
|
||||
----------------------------------------
|
||||
@@ -1,6 +1,6 @@
|
||||
.. _`noseintegration`:
|
||||
|
||||
How to run tests written for nose
|
||||
Running tests written for nose
|
||||
=======================================
|
||||
|
||||
``pytest`` has basic support for running tests written for nose_.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user