summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--CHANGELOG.rst3
-rw-r--r--changelog/2049.bugfix.rst1
-rw-r--r--changelog/6189.bugfix.rst1
-rw-r--r--src/_pytest/python.py3
-rw-r--r--src/_pytest/setupplan.py3
-rw-r--r--testing/acceptance_test.py1
-rw-r--r--testing/test_collection.py11
-rw-r--r--testing/test_setupplan.py91
9 files changed, 109 insertions, 7 deletions
diff --git a/AUTHORS b/AUTHORS
index ee275083a..14c465571 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -135,6 +135,7 @@ Jordan Guymon
Jordan Moldow
Jordan Speicher
Joseph Hunkeler
+Josh Karpel
Joshua Bronson
Jurko Gospodnetić
Justyna Janczyszyn
@@ -264,6 +265,7 @@ Virgil Dupras
Vitaly Lashmanov
Vlad Dragos
Volodymyr Piskun
+Wei Lin
Wil Cooley
William Lee
Wim Glenn
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index b1a988de8..e9ac09c8e 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1901,7 +1901,8 @@ Features
live-logging is enabled and/or when they are logged to a file.
-- `#3985 <https://github.com/pytest-dev/pytest/issues/3985>`_: Introduce ``tmp_path`` as a fixture providing a Path object.
+- `#3985 <https://github.com/pytest-dev/pytest/issues/3985>`_: Introduce ``tmp_path`` as a fixture providing a Path object. Also introduce ``tmp_path_factory`` as
+ a session-scoped fixture for creating arbitrary temporary directories from any other fixture or test.
- `#4013 <https://github.com/pytest-dev/pytest/issues/4013>`_: Deprecation warnings are now shown even if you customize the warnings filters yourself. In the previous version
diff --git a/changelog/2049.bugfix.rst b/changelog/2049.bugfix.rst
new file mode 100644
index 000000000..395396bd3
--- /dev/null
+++ b/changelog/2049.bugfix.rst
@@ -0,0 +1 @@
+Fix ``-setup-plan`` showing inaccurate information about fixture lifetimes.
diff --git a/changelog/6189.bugfix.rst b/changelog/6189.bugfix.rst
new file mode 100644
index 000000000..060a2260a
--- /dev/null
+++ b/changelog/6189.bugfix.rst
@@ -0,0 +1 @@
+Fix incorrect result of ``getmodpath`` method.
diff --git a/src/_pytest/python.py b/src/_pytest/python.py
index 4702e0659..bf0812339 100644
--- a/src/_pytest/python.py
+++ b/src/_pytest/python.py
@@ -287,8 +287,7 @@ class PyobjMixin(PyobjContext):
break
parts.append(name)
parts.reverse()
- s = ".".join(parts)
- return s.replace(".[", "[")
+ return ".".join(parts)
def reportinfo(self) -> Tuple[str, int, str]:
# XXX caching?
diff --git a/src/_pytest/setupplan.py b/src/_pytest/setupplan.py
index 697746f20..6fdd3aed0 100644
--- a/src/_pytest/setupplan.py
+++ b/src/_pytest/setupplan.py
@@ -16,7 +16,8 @@ def pytest_addoption(parser):
def pytest_fixture_setup(fixturedef, request):
# Will return a dummy fixture if the setuponly option is provided.
if request.config.option.setupplan:
- fixturedef.cached_result = (None, None, None)
+ my_cache_key = fixturedef.cache_key(request)
+ fixturedef.cached_result = (None, my_cache_key, None)
return fixturedef.cached_result
diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py
index 578ab45eb..8f7be14be 100644
--- a/testing/acceptance_test.py
+++ b/testing/acceptance_test.py
@@ -760,7 +760,6 @@ class TestInvocationVariants:
result = testdir.runpytest(str(p) + "::test", "--doctest-modules")
result.stdout.fnmatch_lines(["*1 passed*"])
- @pytest.mark.skipif(not hasattr(os, "symlink"), reason="requires symlinks")
def test_cmdline_python_package_symlink(self, testdir, monkeypatch):
"""
test --pyargs option with packages with path containing symlink can
diff --git a/testing/test_collection.py b/testing/test_collection.py
index 303738d67..b791ac6f9 100644
--- a/testing/test_collection.py
+++ b/testing/test_collection.py
@@ -685,6 +685,8 @@ class Test_genitems:
def test_example_items1(self, testdir):
p = testdir.makepyfile(
"""
+ import pytest
+
def testone():
pass
@@ -693,19 +695,24 @@ class Test_genitems:
pass
class TestY(TestX):
- pass
+ @pytest.mark.parametrize("arg0", [".["])
+ def testmethod_two(self, arg0):
+ pass
"""
)
items, reprec = testdir.inline_genitems(p)
- assert len(items) == 3
+ assert len(items) == 4
assert items[0].name == "testone"
assert items[1].name == "testmethod_one"
assert items[2].name == "testmethod_one"
+ assert items[3].name == "testmethod_two[.[]"
# let's also test getmodpath here
assert items[0].getmodpath() == "testone"
assert items[1].getmodpath() == "TestX.testmethod_one"
assert items[2].getmodpath() == "TestY.testmethod_one"
+ # PR #6202: Fix incorrect result of getmodpath method. (Resolves issue #6189)
+ assert items[3].getmodpath() == "TestY.testmethod_two[.[]"
s = items[0].getmodpath(stopatmodule=False)
assert s.endswith("test_example_items1.testone")
diff --git a/testing/test_setupplan.py b/testing/test_setupplan.py
index e323ba240..a44474dd1 100644
--- a/testing/test_setupplan.py
+++ b/testing/test_setupplan.py
@@ -17,3 +17,94 @@ def test_show_fixtures_and_test(testdir, dummy_yaml_custom_test):
result.stdout.fnmatch_lines(
["*SETUP F arg*", "*test_arg (fixtures used: arg)", "*TEARDOWN F arg*"]
)
+
+
+def test_show_multi_test_fixture_setup_and_teardown_correctly_simple(testdir):
+ """
+ Verify that when a fixture lives for longer than a single test, --setup-plan
+ correctly displays the SETUP/TEARDOWN indicators the right number of times.
+
+ As reported in https://github.com/pytest-dev/pytest/issues/2049
+ --setup-plan was showing SETUP/TEARDOWN on every test, even when the fixture
+ should persist through multiple tests.
+
+ (Note that this bug never affected actual test execution, which used the
+ correct fixture lifetimes. It was purely a display bug for --setup-plan, and
+ did not affect the related --setup-show or --setup-only.)
+ """
+ testdir.makepyfile(
+ """
+ import pytest
+ @pytest.fixture(scope = 'class')
+ def fix():
+ return object()
+ class TestClass:
+ def test_one(self, fix):
+ assert False
+ def test_two(self, fix):
+ assert False
+ """
+ )
+
+ result = testdir.runpytest("--setup-plan")
+ assert result.ret == 0
+
+ setup_fragment = "SETUP C fix"
+ setup_count = 0
+
+ teardown_fragment = "TEARDOWN C fix"
+ teardown_count = 0
+
+ for line in result.stdout.lines:
+ if setup_fragment in line:
+ setup_count += 1
+ if teardown_fragment in line:
+ teardown_count += 1
+
+ # before the fix this tests, there would have been a setup/teardown
+ # message for each test, so the counts would each have been 2
+ assert setup_count == 1
+ assert teardown_count == 1
+
+
+def test_show_multi_test_fixture_setup_and_teardown_same_as_setup_show(testdir):
+ """
+ Verify that SETUP/TEARDOWN messages match what comes out of --setup-show.
+ """
+ testdir.makepyfile(
+ """
+ import pytest
+ @pytest.fixture(scope = 'session')
+ def sess():
+ return True
+ @pytest.fixture(scope = 'module')
+ def mod():
+ return True
+ @pytest.fixture(scope = 'class')
+ def cls():
+ return True
+ @pytest.fixture(scope = 'function')
+ def func():
+ return True
+ def test_outside(sess, mod, cls, func):
+ assert True
+ class TestCls:
+ def test_one(self, sess, mod, cls, func):
+ assert True
+ def test_two(self, sess, mod, cls, func):
+ assert True
+ """
+ )
+
+ plan_result = testdir.runpytest("--setup-plan")
+ show_result = testdir.runpytest("--setup-show")
+
+ # the number and text of these lines should be identical
+ plan_lines = [
+ l for l in plan_result.stdout.lines if "SETUP" in l or "TEARDOWN" in l
+ ]
+ show_lines = [
+ l for l in show_result.stdout.lines if "SETUP" in l or "TEARDOWN" in l
+ ]
+
+ assert plan_lines == show_lines