Skip to content

Commit b031a7c

Browse files
ssbarneanicoddemusgraingertaltendky
authored
Smoke tests for assorted plugins (#7721)
Co-authored-by: Bruno Oliveira <[email protected]> Co-authored-by: Thomas Grainger <[email protected]> Co-authored-by: Kyle Altendorf <[email protected]>
1 parent 9f164b7 commit b031a7c

19 files changed

+190
-4
lines changed

.github/workflows/main.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141

4242
"docs",
4343
"doctesting",
44+
"plugins",
4445
]
4546

4647
include:
@@ -111,6 +112,11 @@ jobs:
111112
tox_env: "py38-xdist"
112113
use_coverage: true
113114

115+
- name: "plugins"
116+
python: "3.7"
117+
os: ubuntu-latest
118+
tox_env: "plugins"
119+
114120
- name: "docs"
115121
python: "3.7"
116122
os: ubuntu-latest

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ write_to = "src/_pytest/_version.py"
1313
[tool.pytest.ini_options]
1414
minversion = "2.0"
1515
addopts = "-rfEX -p pytester --strict-markers"
16-
python_files = ["test_*.py", "*_test.py", "testing/*/*.py"]
16+
python_files = ["test_*.py", "*_test.py", "testing/python/*.py"]
1717
python_classes = ["Test", "Acceptance"]
1818
python_functions = ["test"]
1919
# NOTE: "doc" is not included here, but gets tested explicitly via "doctesting".

src/_pytest/config/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,10 @@ def _preparse(self, args: List[str], addopts: bool = True) -> None:
11671167
self.pluginmanager.load_setuptools_entrypoints("pytest11")
11681168
self.pluginmanager.consider_env()
11691169

1170+
self.known_args_namespace = self._parser.parse_known_args(
1171+
args, namespace=copy.copy(self.known_args_namespace)
1172+
)
1173+
11701174
self._validate_plugins()
11711175
self._warn_about_skipped_plugins()
11721176

src/_pytest/python.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,10 @@ def async_warn_and_skip(nodeid: str) -> None:
164164
msg += (
165165
"You need to install a suitable plugin for your async framework, for example:\n"
166166
)
167+
msg += " - anyio\n"
167168
msg += " - pytest-asyncio\n"
168-
msg += " - pytest-trio\n"
169169
msg += " - pytest-tornasync\n"
170+
msg += " - pytest-trio\n"
170171
msg += " - pytest-twisted"
171172
warnings.warn(PytestUnhandledCoroutineWarning(msg.format(nodeid)))
172173
skip(msg="async def function and no async plugin installed (see warnings)")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.html
2+
assets/
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
This folder contains tests and support files for smoke testing popular plugins against the current pytest version.
2+
3+
The objective is to gauge if any intentional or unintentional changes in pytest break plugins.
4+
5+
As a rule of thumb, we should add plugins here:
6+
7+
1. That are used at large. This might be subjective in some cases, but if answer is yes to
8+
the question: *if a new release of pytest causes pytest-X to break, will this break a ton of test suites out there?*.
9+
2. That don't have large external dependencies: such as external services.
10+
11+
Besides adding the plugin as dependency, we should also add a quick test which uses some
12+
minimal part of the plugin, a smoke test. Also consider reusing one of the existing tests if that's
13+
possible.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Feature: Buy things with apple
2+
3+
Scenario: Buy fruits
4+
Given A wallet with 50
5+
6+
When I buy some apples for 1
7+
And I buy some bananas for 2
8+
9+
Then I have 47 left
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from pytest_bdd import given
2+
from pytest_bdd import scenario
3+
from pytest_bdd import then
4+
from pytest_bdd import when
5+
6+
import pytest
7+
8+
9+
@scenario("bdd_wallet.feature", "Buy fruits")
10+
def test_publish():
11+
pass
12+
13+
14+
@pytest.fixture
15+
def wallet():
16+
class Wallet:
17+
amount = 0
18+
19+
return Wallet()
20+
21+
22+
@given("A wallet with 50")
23+
def fill_wallet(wallet):
24+
wallet.amount = 50
25+
26+
27+
@when("I buy some apples for 1")
28+
def buy_apples(wallet):
29+
wallet.amount -= 1
30+
31+
32+
@when("I buy some bananas for 2")
33+
def buy_bananas(wallet):
34+
wallet.amount -= 2
35+
36+
37+
@then("I have 47 left")
38+
def check(wallet):
39+
assert wallet.amount == 47
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SECRET_KEY = "mysecret"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[pytest]
2+
addopts = --strict-markers
3+
filterwarnings =
4+
error::pytest.PytestWarning
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import anyio
2+
3+
import pytest
4+
5+
6+
@pytest.mark.anyio
7+
async def test_sleep():
8+
await anyio.sleep(0)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import asyncio
2+
3+
import pytest
4+
5+
6+
@pytest.mark.asyncio
7+
async def test_sleep():
8+
await asyncio.sleep(0)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def test_mocker(mocker):
2+
mocker.MagicMock()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import trio
2+
3+
import pytest
4+
5+
6+
@pytest.mark.trio
7+
async def test_sleep():
8+
await trio.sleep(0)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import pytest_twisted
2+
from twisted.internet.task import deferLater
3+
4+
5+
def sleep():
6+
import twisted.internet.reactor
7+
8+
return deferLater(clock=twisted.internet.reactor, delay=0)
9+
10+
11+
@pytest_twisted.inlineCallbacks
12+
def test_inlineCallbacks():
13+
yield sleep()
14+
15+
16+
@pytest_twisted.ensureDeferred
17+
async def test_inlineCallbacks_async():
18+
await sleep()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import pytest
2+
3+
4+
def test_foo():
5+
assert True
6+
7+
8+
@pytest.mark.parametrize("i", range(3))
9+
def test_bar(i):
10+
assert True

testing/test_assertrewrite.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -990,7 +990,7 @@ def atomic_write_failed(fn, mode="r", overwrite=False):
990990
e = OSError()
991991
e.errno = 10
992992
raise e
993-
yield
993+
yield # type:ignore[unreachable]
994994

995995
monkeypatch.setattr(
996996
_pytest.assertion.rewrite, "atomic_write", atomic_write_failed
@@ -1597,7 +1597,7 @@ def test_get_cache_dir(self, monkeypatch, prefix, source, expected):
15971597
if prefix:
15981598
if sys.version_info < (3, 8):
15991599
pytest.skip("pycache_prefix not available in py<38")
1600-
monkeypatch.setattr(sys, "pycache_prefix", prefix)
1600+
monkeypatch.setattr(sys, "pycache_prefix", prefix) # type:ignore
16011601

16021602
assert get_cache_dir(Path(source)) == Path(expected)
16031603

testing/test_config.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,25 @@ def my_dists():
422422
else:
423423
testdir.parseconfig()
424424

425+
def test_early_config_cmdline(self, testdir, monkeypatch):
426+
"""early_config contains options registered by third-party plugins.
427+
428+
This is a regression involving pytest-cov (and possibly others) introduced in #7700.
429+
"""
430+
testdir.makepyfile(
431+
myplugin="""
432+
def pytest_addoption(parser):
433+
parser.addoption('--foo', default=None, dest='foo')
434+
435+
def pytest_load_initial_conftests(early_config, parser, args):
436+
assert early_config.known_args_namespace.foo == "1"
437+
"""
438+
)
439+
monkeypatch.setenv("PYTEST_PLUGINS", "myplugin")
440+
testdir.syspathinsert()
441+
result = testdir.runpytest("--foo=1")
442+
result.stdout.fnmatch_lines("* no tests ran in *")
443+
425444

426445
class TestConfigCmdlineParsing:
427446
def test_parsing_again_fails(self, testdir):

tox.ini

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ envlist =
1313
pypy3
1414
py37-{pexpect,xdist,unittestextras,numpy,pluggymaster}
1515
doctesting
16+
plugins
1617
py37-freeze
1718
docs
1819
docs-checklinks
@@ -114,6 +115,39 @@ commands =
114115
rm -rf {envdir}/.pytest_cache
115116
make regen
116117

118+
[testenv:plugins]
119+
pip_pre=true
120+
changedir = testing/plugins_integration
121+
deps =
122+
anyio[curio,trio]
123+
django
124+
pytest-asyncio
125+
pytest-bdd
126+
pytest-cov
127+
pytest-django
128+
pytest-flakes
129+
pytest-html
130+
pytest-mock
131+
pytest-sugar
132+
pytest-trio
133+
pytest-twisted
134+
twisted
135+
pytest-xvfb
136+
setenv =
137+
PYTHONPATH=.
138+
commands =
139+
pip check
140+
pytest bdd_wallet.py
141+
pytest --cov=. simple_integration.py
142+
pytest --ds=django_settings simple_integration.py
143+
pytest --html=simple.html simple_integration.py
144+
pytest pytest_anyio_integration.py
145+
pytest pytest_asyncio_integration.py
146+
pytest pytest_mock_integration.py
147+
pytest pytest_trio_integration.py
148+
pytest pytest_twisted_integration.py
149+
pytest simple_integration.py --force-sugar --flakes
150+
117151
[testenv:py37-freeze]
118152
changedir = testing/freeze
119153
deps =

0 commit comments

Comments
 (0)