diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index beb501785..1b6e85fd8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -123,7 +123,8 @@ jobs: with: fetch-depth: 0 - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v2 + # https://github.com/actions/setup-python/issues/171 + uses: actions/setup-python@v2.1.4 with: python-version: ${{ matrix.python }} - name: Install dependencies diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index fee0770eb..27c76a043 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -528,7 +528,7 @@ class FSCollector(Collector): warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) return self.session.gethookproxy(fspath) - def isinitpath(self, path: py.path.local) -> bool: + def isinitpath(self, path: "os.PathLike[str]") -> bool: warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) return self.session.isinitpath(path) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 18e449b93..018e368f4 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -660,7 +660,7 @@ class Package(Module): warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) return self.session.gethookproxy(fspath) - def isinitpath(self, path: py.path.local) -> bool: + def isinitpath(self, path: "os.PathLike[str]") -> bool: warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) return self.session.isinitpath(path) diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index d213414ee..6d92d181f 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -5,24 +5,23 @@ from unittest import mock import pytest from _pytest import deprecated from _pytest.pytester import Pytester -from _pytest.pytester import Testdir @pytest.mark.parametrize("attribute", pytest.collect.__all__) # type: ignore # false positive due to dynamic attribute -def test_pytest_collect_module_deprecated(attribute): +def test_pytest_collect_module_deprecated(attribute) -> None: with pytest.warns(DeprecationWarning, match=attribute): getattr(pytest.collect, attribute) @pytest.mark.parametrize("plugin", sorted(deprecated.DEPRECATED_EXTERNAL_PLUGINS)) @pytest.mark.filterwarnings("default") -def test_external_plugins_integrated(testdir, plugin): - testdir.syspathinsert() - testdir.makepyfile(**{plugin: ""}) +def test_external_plugins_integrated(pytester: Pytester, plugin) -> None: + pytester.syspathinsert() + pytester.makepyfile(**{plugin: ""}) with pytest.warns(pytest.PytestConfigWarning): - testdir.parseconfig("-p", plugin) + pytester.parseconfig("-p", plugin) def test_fillfuncargs_is_deprecated() -> None: @@ -49,32 +48,32 @@ def test_fillfixtures_is_deprecated() -> None: _pytest.fixtures.fillfixtures(mock.Mock()) -def test_minus_k_dash_is_deprecated(testdir) -> None: - threepass = testdir.makepyfile( +def test_minus_k_dash_is_deprecated(pytester: Pytester) -> None: + threepass = pytester.makepyfile( test_threepass=""" def test_one(): assert 1 def test_two(): assert 1 def test_three(): assert 1 """ ) - result = testdir.runpytest("-k=-test_two", threepass) + result = pytester.runpytest("-k=-test_two", threepass) result.stdout.fnmatch_lines(["*The `-k '-expr'` syntax*deprecated*"]) -def test_minus_k_colon_is_deprecated(testdir) -> None: - threepass = testdir.makepyfile( +def test_minus_k_colon_is_deprecated(pytester: Pytester) -> None: + threepass = pytester.makepyfile( test_threepass=""" def test_one(): assert 1 def test_two(): assert 1 def test_three(): assert 1 """ ) - result = testdir.runpytest("-k", "test_two:", threepass) + result = pytester.runpytest("-k", "test_two:", threepass) result.stdout.fnmatch_lines(["*The `-k 'expr:'` syntax*deprecated*"]) -def test_fscollector_gethookproxy_isinitpath(testdir: Testdir) -> None: - module = testdir.getmodulecol( +def test_fscollector_gethookproxy_isinitpath(pytester: Pytester) -> None: + module = pytester.getmodulecol( """ def test_foo(): pass """, @@ -85,16 +84,16 @@ def test_fscollector_gethookproxy_isinitpath(testdir: Testdir) -> None: assert isinstance(package, pytest.Package) with pytest.warns(pytest.PytestDeprecationWarning, match="gethookproxy"): - package.gethookproxy(testdir.tmpdir) + package.gethookproxy(pytester.path) with pytest.warns(pytest.PytestDeprecationWarning, match="isinitpath"): - package.isinitpath(testdir.tmpdir) + package.isinitpath(pytester.path) # The methods on Session are *not* deprecated. session = module.session with warnings.catch_warnings(record=True) as rec: - session.gethookproxy(testdir.tmpdir) - session.isinitpath(testdir.tmpdir) + session.gethookproxy(pytester.path) + session.isinitpath(pytester.path) assert len(rec) == 0 diff --git a/testing/test_cacheprovider.py b/testing/test_cacheprovider.py index 7f0827bd4..ebd455593 100644 --- a/testing/test_cacheprovider.py +++ b/testing/test_cacheprovider.py @@ -1050,7 +1050,7 @@ class TestLastFailed: class TestNewFirst: - def test_newfirst_usecase(self, pytester: Pytester, testdir) -> None: + def test_newfirst_usecase(self, pytester: Pytester) -> None: pytester.makepyfile( **{ "test_1/test_1.py": """ diff --git a/testing/test_collection.py b/testing/test_collection.py index 862c1aba8..2d03fda39 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -6,6 +6,8 @@ import textwrap from pathlib import Path from typing import List +import py.path + import pytest from _pytest.config import ExitCode from _pytest.fixtures import FixtureRequest @@ -16,7 +18,6 @@ from _pytest.nodes import Item from _pytest.pathlib import symlink_or_skip from _pytest.pytester import HookRecorder from _pytest.pytester import Pytester -from _pytest.pytester import Testdir def ensure_file(file_path: Path) -> Path: @@ -206,15 +207,17 @@ class TestCollectFS: "Activate.ps1", ), ) - def test__in_venv(self, testdir: Testdir, fname: str) -> None: + def test__in_venv(self, pytester: Pytester, fname: str) -> None: """Directly test the virtual env detection function""" bindir = "Scripts" if sys.platform.startswith("win") else "bin" # no bin/activate, not a virtualenv - base_path = testdir.tmpdir.mkdir("venv") - assert _in_venv(base_path) is False + base_path = pytester.mkdir("venv") + assert _in_venv(py.path.local(base_path)) is False # with bin/activate, totally a virtualenv - base_path.ensure(bindir, fname) - assert _in_venv(base_path) is True + bin_path = base_path.joinpath(bindir) + bin_path.mkdir() + bin_path.joinpath(fname).touch() + assert _in_venv(py.path.local(base_path)) is True def test_custom_norecursedirs(self, pytester: Pytester) -> None: pytester.makeini( @@ -264,7 +267,7 @@ class TestCollectFS: class TestCollectPluginHookRelay: - def test_pytest_collect_file(self, testdir: Testdir) -> None: + def test_pytest_collect_file(self, pytester: Pytester) -> None: wascalled = [] class Plugin: @@ -273,8 +276,8 @@ class TestCollectPluginHookRelay: # Ignore hidden files, e.g. .testmondata. wascalled.append(path) - testdir.makefile(".abc", "xyz") - pytest.main(testdir.tmpdir, plugins=[Plugin()]) + pytester.makefile(".abc", "xyz") + pytest.main(py.path.local(pytester.path), plugins=[Plugin()]) assert len(wascalled) == 1 assert wascalled[0].ext == ".abc" @@ -1336,7 +1339,7 @@ def test_does_not_put_src_on_path(pytester: Pytester) -> None: assert result.ret == ExitCode.OK -def test_fscollector_from_parent(testdir: Testdir, request: FixtureRequest) -> None: +def test_fscollector_from_parent(pytester: Pytester, request: FixtureRequest) -> None: """Ensure File.from_parent can forward custom arguments to the constructor. Context: https://github.com/pytest-dev/pytest-cpp/pull/47 @@ -1352,7 +1355,7 @@ def test_fscollector_from_parent(testdir: Testdir, request: FixtureRequest) -> N return super().from_parent(parent=parent, fspath=fspath, x=x) collector = MyCollector.from_parent( - parent=request.session, fspath=testdir.tmpdir / "foo", x=10 + parent=request.session, fspath=py.path.local(pytester.path) / "foo", x=10 ) assert collector.x == 10 diff --git a/testing/test_debugging.py b/testing/test_debugging.py index ed96f7ec7..8218b7a0e 100644 --- a/testing/test_debugging.py +++ b/testing/test_debugging.py @@ -21,11 +21,10 @@ _ENVIRON_PYTHONBREAKPOINT = os.environ.get("PYTHONBREAKPOINT", "") @pytest.fixture(autouse=True) -def pdb_env(request): +def pdb_env(request, monkeypatch: MonkeyPatch): if "pytester" in request.fixturenames: # Disable pdb++ with inner tests. - pytester = request.getfixturevalue("testdir") - pytester.monkeypatch.setenv("PDBPP_HIJACK_PDB", "0") + monkeypatch.setenv("PDBPP_HIJACK_PDB", "0") def runpdb_and_get_report(pytester: Pytester, source: str): diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 006bea962..3e445dcef 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -4,24 +4,31 @@ from datetime import datetime from pathlib import Path from typing import cast from typing import List +from typing import Optional from typing import Tuple from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union from xml.dom import minidom -import py import xmlschema import pytest from _pytest.config import Config from _pytest.junitxml import bin_xml_escape from _pytest.junitxml import LogXML +from _pytest.monkeypatch import MonkeyPatch +from _pytest.pytester import Pytester +from _pytest.pytester import RunResult from _pytest.reports import BaseReport from _pytest.reports import TestReport from _pytest.store import Store +T = TypeVar("T") + @pytest.fixture(scope="session") -def schema(): +def schema() -> xmlschema.XMLSchema: """Return an xmlschema.XMLSchema object for the junit-10.xsd file.""" fn = Path(__file__).parent / "example_scripts/junit-10.xsd" with fn.open() as f: @@ -29,7 +36,7 @@ def schema(): @pytest.fixture -def run_and_parse(testdir, schema): +def run_and_parse(pytester: Pytester, schema: xmlschema.XMLSchema) -> T: """Fixture that returns a function that can be used to execute pytest and return the parsed ``DomNode`` of the root xml node. @@ -37,18 +44,20 @@ def run_and_parse(testdir, schema): "xunit2" is also automatically validated against the schema. """ - def run(*args, family="xunit1"): + def run( + *args: Union[str, "os.PathLike[str]"], family: Optional[str] = "xunit1", + ) -> Tuple[RunResult, "DomNode"]: if family: args = ("-o", "junit_family=" + family) + args - xml_path = testdir.tmpdir.join("junit.xml") - result = testdir.runpytest("--junitxml=%s" % xml_path, *args) + xml_path = pytester.path.joinpath("junit.xml") + result = pytester.runpytest("--junitxml=%s" % xml_path, *args) if family == "xunit2": with xml_path.open() as f: schema.validate(f) xmldoc = minidom.parse(str(xml_path)) return result, DomNode(xmldoc) - return run + return cast(T, run) def assert_attr(node, **kwargs): @@ -130,8 +139,10 @@ parametrize_families = pytest.mark.parametrize("xunit_family", ["xunit1", "xunit class TestPython: @parametrize_families - def test_summing_simple(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_summing_simple( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest def test_pass(): @@ -154,8 +165,10 @@ class TestPython: node.assert_attr(name="pytest", errors=0, failures=1, skipped=2, tests=5) @parametrize_families - def test_summing_simple_with_errors(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_summing_simple_with_errors( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @pytest.fixture @@ -181,8 +194,10 @@ class TestPython: node.assert_attr(name="pytest", errors=1, failures=2, skipped=1, tests=5) @parametrize_families - def test_hostname_in_xml(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_hostname_in_xml( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ def test_pass(): pass @@ -193,8 +208,10 @@ class TestPython: node.assert_attr(hostname=platform.node()) @parametrize_families - def test_timestamp_in_xml(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_timestamp_in_xml( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ def test_pass(): pass @@ -206,8 +223,10 @@ class TestPython: timestamp = datetime.strptime(node["timestamp"], "%Y-%m-%dT%H:%M:%S.%f") assert start_time <= timestamp < datetime.now() - def test_timing_function(self, testdir, run_and_parse, mock_timing): - testdir.makepyfile( + def test_timing_function( + self, pytester: Pytester, run_and_parse, mock_timing + ) -> None: + pytester.makepyfile( """ from _pytest import timing def setup_module(): @@ -226,8 +245,12 @@ class TestPython: @pytest.mark.parametrize("duration_report", ["call", "total"]) def test_junit_duration_report( - self, testdir, monkeypatch, duration_report, run_and_parse - ): + self, + pytester: Pytester, + monkeypatch: MonkeyPatch, + duration_report, + run_and_parse, + ) -> None: # mock LogXML.node_reporter so it always sets a known duration to each test report object original_node_reporter = LogXML.node_reporter @@ -239,7 +262,7 @@ class TestPython: monkeypatch.setattr(LogXML, "node_reporter", node_reporter_wrapper) - testdir.makepyfile( + pytester.makepyfile( """ def test_foo(): pass @@ -256,8 +279,8 @@ class TestPython: assert val == 1.0 @parametrize_families - def test_setup_error(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_setup_error(self, pytester: Pytester, run_and_parse, xunit_family) -> None: + pytester.makepyfile( """ import pytest @@ -279,8 +302,10 @@ class TestPython: assert "ValueError" in fnode.toxml() @parametrize_families - def test_teardown_error(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_teardown_error( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @@ -302,8 +327,10 @@ class TestPython: assert "ValueError" in fnode.toxml() @parametrize_families - def test_call_failure_teardown_error(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_call_failure_teardown_error( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @@ -331,8 +358,10 @@ class TestPython: ) @parametrize_families - def test_skip_contains_name_reason(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_skip_contains_name_reason( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest def test_skip(): @@ -349,8 +378,10 @@ class TestPython: snode.assert_attr(type="pytest.skip", message="hello23") @parametrize_families - def test_mark_skip_contains_name_reason(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_mark_skip_contains_name_reason( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @pytest.mark.skip(reason="hello24") @@ -371,9 +402,9 @@ class TestPython: @parametrize_families def test_mark_skipif_contains_name_reason( - self, testdir, run_and_parse, xunit_family - ): - testdir.makepyfile( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest GLOBAL_CONDITION = True @@ -395,9 +426,9 @@ class TestPython: @parametrize_families def test_mark_skip_doesnt_capture_output( - self, testdir, run_and_parse, xunit_family - ): - testdir.makepyfile( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @pytest.mark.skip(reason="foo") @@ -411,8 +442,10 @@ class TestPython: assert "bar!" not in node_xml @parametrize_families - def test_classname_instance(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_classname_instance( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ class TestClass(object): def test_method(self): @@ -429,9 +462,11 @@ class TestPython: ) @parametrize_families - def test_classname_nested_dir(self, testdir, run_and_parse, xunit_family): - p = testdir.tmpdir.ensure("sub", "test_hello.py") - p.write("def test_func(): 0/0") + def test_classname_nested_dir( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + p = pytester.mkdir("sub").joinpath("test_hello.py") + p.write_text("def test_func(): 0/0") result, dom = run_and_parse(family=xunit_family) assert result.ret node = dom.find_first_by_tag("testsuite") @@ -440,9 +475,11 @@ class TestPython: tnode.assert_attr(classname="sub.test_hello", name="test_func") @parametrize_families - def test_internal_error(self, testdir, run_and_parse, xunit_family): - testdir.makeconftest("def pytest_runtest_protocol(): 0 / 0") - testdir.makepyfile("def test_function(): pass") + def test_internal_error( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makeconftest("def pytest_runtest_protocol(): 0 / 0") + pytester.makepyfile("def test_function(): pass") result, dom = run_and_parse(family=xunit_family) assert result.ret node = dom.find_first_by_tag("testsuite") @@ -458,9 +495,9 @@ class TestPython: ) @parametrize_families def test_failure_function( - self, testdir, junit_logging, run_and_parse, xunit_family - ): - testdir.makepyfile( + self, pytester: Pytester, junit_logging, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import logging import sys @@ -521,8 +558,10 @@ class TestPython: ), "Found unexpected content: system-err" @parametrize_families - def test_failure_verbose_message(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_failure_verbose_message( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import sys def test_fail(): @@ -536,8 +575,10 @@ class TestPython: fnode.assert_attr(message="AssertionError: An error\nassert 0") @parametrize_families - def test_failure_escape(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_failure_escape( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @pytest.mark.parametrize('arg1', "<&'", ids="<&'") @@ -564,8 +605,10 @@ class TestPython: assert "%s\n" % char in text @parametrize_families - def test_junit_prefixing(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_junit_prefixing( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ def test_func(): assert 0 @@ -586,8 +629,10 @@ class TestPython: ) @parametrize_families - def test_xfailure_function(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_xfailure_function( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest def test_xfail(): @@ -604,8 +649,10 @@ class TestPython: fnode.assert_attr(type="pytest.xfail", message="42") @parametrize_families - def test_xfailure_marker(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_xfailure_marker( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @pytest.mark.xfail(reason="42") @@ -625,8 +672,10 @@ class TestPython: @pytest.mark.parametrize( "junit_logging", ["no", "log", "system-out", "system-err", "out-err", "all"] ) - def test_xfail_captures_output_once(self, testdir, junit_logging, run_and_parse): - testdir.makepyfile( + def test_xfail_captures_output_once( + self, pytester: Pytester, junit_logging, run_and_parse + ) -> None: + pytester.makepyfile( """ import sys import pytest @@ -652,8 +701,10 @@ class TestPython: assert len(tnode.find_by_tag("system-out")) == 0 @parametrize_families - def test_xfailure_xpass(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_xfailure_xpass( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @pytest.mark.xfail @@ -669,8 +720,10 @@ class TestPython: tnode.assert_attr(classname="test_xfailure_xpass", name="test_xpass") @parametrize_families - def test_xfailure_xpass_strict(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile( + def test_xfailure_xpass_strict( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile( """ import pytest @pytest.mark.xfail(strict=True, reason="This needs to fail!") @@ -688,8 +741,10 @@ class TestPython: fnode.assert_attr(message="[XPASS(strict)] This needs to fail!") @parametrize_families - def test_collect_error(self, testdir, run_and_parse, xunit_family): - testdir.makepyfile("syntax error") + def test_collect_error( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makepyfile("syntax error") result, dom = run_and_parse(family=xunit_family) assert result.ret node = dom.find_first_by_tag("testsuite") @@ -699,9 +754,9 @@ class TestPython: fnode.assert_attr(message="collection failure") assert "SyntaxError" in fnode.toxml() - def test_unicode(self, testdir, run_and_parse): + def test_unicode(self, pytester: Pytester, run_and_parse) -> None: value = "hx\xc4\x85\xc4\x87\n" - testdir.makepyfile( + pytester.makepyfile( """\ # coding: latin1 def test_hello(): @@ -716,9 +771,9 @@ class TestPython: fnode = tnode.find_first_by_tag("failure") assert "hx" in fnode.toxml() - def test_assertion_binchars(self, testdir, run_and_parse): + def test_assertion_binchars(self, pytester: Pytester, run_and_parse) -> None: """This test did fail when the escaping wasn't strict.""" - testdir.makepyfile( + pytester.makepyfile( """ M1 = '\x01\x02\x03\x04' @@ -732,8 +787,10 @@ class TestPython: print(dom.toxml()) @pytest.mark.parametrize("junit_logging", ["no", "system-out"]) - def test_pass_captures_stdout(self, testdir, run_and_parse, junit_logging): - testdir.makepyfile( + def test_pass_captures_stdout( + self, pytester: Pytester, run_and_parse, junit_logging + ) -> None: + pytester.makepyfile( """ def test_pass(): print('hello-stdout') @@ -753,8 +810,10 @@ class TestPython: ), "'hello-stdout' should be in system-out" @pytest.mark.parametrize("junit_logging", ["no", "system-err"]) - def test_pass_captures_stderr(self, testdir, run_and_parse, junit_logging): - testdir.makepyfile( + def test_pass_captures_stderr( + self, pytester: Pytester, run_and_parse, junit_logging + ) -> None: + pytester.makepyfile( """ import sys def test_pass(): @@ -775,8 +834,10 @@ class TestPython: ), "'hello-stderr' should be in system-err" @pytest.mark.parametrize("junit_logging", ["no", "system-out"]) - def test_setup_error_captures_stdout(self, testdir, run_and_parse, junit_logging): - testdir.makepyfile( + def test_setup_error_captures_stdout( + self, pytester: Pytester, run_and_parse, junit_logging + ) -> None: + pytester.makepyfile( """ import pytest @@ -802,8 +863,10 @@ class TestPython: ), "'hello-stdout' should be in system-out" @pytest.mark.parametrize("junit_logging", ["no", "system-err"]) - def test_setup_error_captures_stderr(self, testdir, run_and_parse, junit_logging): - testdir.makepyfile( + def test_setup_error_captures_stderr( + self, pytester: Pytester, run_and_parse, junit_logging + ) -> None: + pytester.makepyfile( """ import sys import pytest @@ -830,8 +893,10 @@ class TestPython: ), "'hello-stderr' should be in system-err" @pytest.mark.parametrize("junit_logging", ["no", "system-out"]) - def test_avoid_double_stdout(self, testdir, run_and_parse, junit_logging): - testdir.makepyfile( + def test_avoid_double_stdout( + self, pytester: Pytester, run_and_parse, junit_logging + ) -> None: + pytester.makepyfile( """ import sys import pytest @@ -858,7 +923,7 @@ class TestPython: assert "hello-stdout teardown" in systemout.toxml() -def test_mangle_test_address(): +def test_mangle_test_address() -> None: from _pytest.junitxml import mangle_test_address address = "::".join(["a/my.py.thing.py", "Class", "()", "method", "[a-1-::]"]) @@ -866,7 +931,7 @@ def test_mangle_test_address(): assert newnames == ["a.my.py.thing", "Class", "method", "[a-1-::]"] -def test_dont_configure_on_workers(tmpdir) -> None: +def test_dont_configure_on_workers(tmp_path: Path) -> None: gotten: List[object] = [] class FakeConfig: @@ -882,8 +947,8 @@ def test_dont_configure_on_workers(tmpdir) -> None: return "pytest" junitprefix = None - # XXX: shouldn't need tmpdir ? - xmlpath = str(tmpdir.join("junix.xml")) + # XXX: shouldn't need tmp_path ? + xmlpath = str(tmp_path.joinpath("junix.xml")) register = gotten.append fake_config = cast(Config, FakeConfig()) @@ -898,8 +963,10 @@ def test_dont_configure_on_workers(tmpdir) -> None: class TestNonPython: @parametrize_families - def test_summing_simple(self, testdir, run_and_parse, xunit_family): - testdir.makeconftest( + def test_summing_simple( + self, pytester: Pytester, run_and_parse, xunit_family + ) -> None: + pytester.makeconftest( """ import pytest def pytest_collect_file(path, parent): @@ -912,7 +979,7 @@ class TestNonPython: return "custom item runtest failed" """ ) - testdir.tmpdir.join("myfile.xyz").write("hello") + pytester.path.joinpath("myfile.xyz").write_text("hello") result, dom = run_and_parse(family=xunit_family) assert result.ret node = dom.find_first_by_tag("testsuite") @@ -925,9 +992,9 @@ class TestNonPython: @pytest.mark.parametrize("junit_logging", ["no", "system-out"]) -def test_nullbyte(testdir, junit_logging): +def test_nullbyte(pytester: Pytester, junit_logging) -> None: # A null byte can not occur in XML (see section 2.2 of the spec) - testdir.makepyfile( + pytester.makepyfile( """ import sys def test_print_nullbyte(): @@ -936,9 +1003,9 @@ def test_nullbyte(testdir, junit_logging): assert False """ ) - xmlf = testdir.tmpdir.join("junit.xml") - testdir.runpytest("--junitxml=%s" % xmlf, "-o", "junit_logging=%s" % junit_logging) - text = xmlf.read() + xmlf = pytester.path.joinpath("junit.xml") + pytester.runpytest("--junitxml=%s" % xmlf, "-o", "junit_logging=%s" % junit_logging) + text = xmlf.read_text() assert "\x00" not in text if junit_logging == "system-out": assert "#x00" in text @@ -947,9 +1014,9 @@ def test_nullbyte(testdir, junit_logging): @pytest.mark.parametrize("junit_logging", ["no", "system-out"]) -def test_nullbyte_replace(testdir, junit_logging): +def test_nullbyte_replace(pytester: Pytester, junit_logging) -> None: # Check if the null byte gets replaced - testdir.makepyfile( + pytester.makepyfile( """ import sys def test_print_nullbyte(): @@ -958,16 +1025,16 @@ def test_nullbyte_replace(testdir, junit_logging): assert False """ ) - xmlf = testdir.tmpdir.join("junit.xml") - testdir.runpytest("--junitxml=%s" % xmlf, "-o", "junit_logging=%s" % junit_logging) - text = xmlf.read() + xmlf = pytester.path.joinpath("junit.xml") + pytester.runpytest("--junitxml=%s" % xmlf, "-o", "junit_logging=%s" % junit_logging) + text = xmlf.read_text() if junit_logging == "system-out": assert "#x0" in text if junit_logging == "no": assert "#x0" not in text -def test_invalid_xml_escape(): +def test_invalid_xml_escape() -> None: # Test some more invalid xml chars, the full range should be # tested really but let's just test the edges of the ranges # instead. @@ -1003,52 +1070,52 @@ def test_invalid_xml_escape(): assert chr(i) == bin_xml_escape(chr(i)) -def test_logxml_path_expansion(tmpdir, monkeypatch): - home_tilde = py.path.local(os.path.expanduser("~")).join("test.xml") - xml_tilde = LogXML("~%stest.xml" % tmpdir.sep, None) - assert xml_tilde.logfile == home_tilde +def test_logxml_path_expansion(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: + home_tilde = Path(os.path.expanduser("~")).joinpath("test.xml") + xml_tilde = LogXML(Path("~", "test.xml"), None) + assert xml_tilde.logfile == str(home_tilde) - monkeypatch.setenv("HOME", str(tmpdir)) + monkeypatch.setenv("HOME", str(tmp_path)) home_var = os.path.normpath(os.path.expandvars("$HOME/test.xml")) - xml_var = LogXML("$HOME%stest.xml" % tmpdir.sep, None) - assert xml_var.logfile == home_var + xml_var = LogXML(Path("$HOME", "test.xml"), None) + assert xml_var.logfile == str(home_var) -def test_logxml_changingdir(testdir): - testdir.makepyfile( +def test_logxml_changingdir(pytester: Pytester) -> None: + pytester.makepyfile( """ def test_func(): import os os.chdir("a") """ ) - testdir.tmpdir.mkdir("a") - result = testdir.runpytest("--junitxml=a/x.xml") + pytester.mkdir("a") + result = pytester.runpytest("--junitxml=a/x.xml") assert result.ret == 0 - assert testdir.tmpdir.join("a/x.xml").check() + assert pytester.path.joinpath("a/x.xml").exists() -def test_logxml_makedir(testdir): +def test_logxml_makedir(pytester: Pytester) -> None: """--junitxml should automatically create directories for the xml file""" - testdir.makepyfile( + pytester.makepyfile( """ def test_pass(): pass """ ) - result = testdir.runpytest("--junitxml=path/to/results.xml") + result = pytester.runpytest("--junitxml=path/to/results.xml") assert result.ret == 0 - assert testdir.tmpdir.join("path/to/results.xml").check() + assert pytester.path.joinpath("path/to/results.xml").exists() -def test_logxml_check_isdir(testdir): +def test_logxml_check_isdir(pytester: Pytester) -> None: """Give an error if --junit-xml is a directory (#2089)""" - result = testdir.runpytest("--junit-xml=.") + result = pytester.runpytest("--junit-xml=.") result.stderr.fnmatch_lines(["*--junitxml must be a filename*"]) -def test_escaped_parametrized_names_xml(testdir, run_and_parse): - testdir.makepyfile( +def test_escaped_parametrized_names_xml(pytester: Pytester, run_and_parse) -> None: + pytester.makepyfile( """\ import pytest @pytest.mark.parametrize('char', ["\\x00"]) @@ -1062,8 +1129,10 @@ def test_escaped_parametrized_names_xml(testdir, run_and_parse): node.assert_attr(name="test_func[\\x00]") -def test_double_colon_split_function_issue469(testdir, run_and_parse): - testdir.makepyfile( +def test_double_colon_split_function_issue469( + pytester: Pytester, run_and_parse +) -> None: + pytester.makepyfile( """ import pytest @pytest.mark.parametrize('param', ["double::colon"]) @@ -1078,8 +1147,8 @@ def test_double_colon_split_function_issue469(testdir, run_and_parse): node.assert_attr(name="test_func[double::colon]") -def test_double_colon_split_method_issue469(testdir, run_and_parse): - testdir.makepyfile( +def test_double_colon_split_method_issue469(pytester: Pytester, run_and_parse) -> None: + pytester.makepyfile( """ import pytest class TestClass(object): @@ -1095,8 +1164,8 @@ def test_double_colon_split_method_issue469(testdir, run_and_parse): node.assert_attr(name="test_func[double::colon]") -def test_unicode_issue368(testdir) -> None: - path = testdir.tmpdir.join("test.xml") +def test_unicode_issue368(pytester: Pytester) -> None: + path = pytester.path.joinpath("test.xml") log = LogXML(str(path), None) ustr = "ВНИ!" @@ -1125,8 +1194,8 @@ def test_unicode_issue368(testdir) -> None: log.pytest_sessionfinish() -def test_record_property(testdir, run_and_parse): - testdir.makepyfile( +def test_record_property(pytester: Pytester, run_and_parse) -> None: + pytester.makepyfile( """ import pytest @@ -1147,8 +1216,8 @@ def test_record_property(testdir, run_and_parse): result.stdout.fnmatch_lines(["*= 1 passed in *"]) -def test_record_property_same_name(testdir, run_and_parse): - testdir.makepyfile( +def test_record_property_same_name(pytester: Pytester, run_and_parse) -> None: + pytester.makepyfile( """ def test_record_with_same_name(record_property): record_property("foo", "bar") @@ -1165,8 +1234,8 @@ def test_record_property_same_name(testdir, run_and_parse): @pytest.mark.parametrize("fixture_name", ["record_property", "record_xml_attribute"]) -def test_record_fixtures_without_junitxml(testdir, fixture_name): - testdir.makepyfile( +def test_record_fixtures_without_junitxml(pytester: Pytester, fixture_name) -> None: + pytester.makepyfile( """ def test_record({fixture_name}): {fixture_name}("foo", "bar") @@ -1174,19 +1243,19 @@ def test_record_fixtures_without_junitxml(testdir, fixture_name): fixture_name=fixture_name ) ) - result = testdir.runpytest() + result = pytester.runpytest() assert result.ret == 0 @pytest.mark.filterwarnings("default") -def test_record_attribute(testdir, run_and_parse): - testdir.makeini( +def test_record_attribute(pytester: Pytester, run_and_parse) -> None: + pytester.makeini( """ [pytest] junit_family = xunit1 """ ) - testdir.makepyfile( + pytester.makepyfile( """ import pytest @@ -1209,15 +1278,17 @@ def test_record_attribute(testdir, run_and_parse): @pytest.mark.filterwarnings("default") @pytest.mark.parametrize("fixture_name", ["record_xml_attribute", "record_property"]) -def test_record_fixtures_xunit2(testdir, fixture_name, run_and_parse): +def test_record_fixtures_xunit2( + pytester: Pytester, fixture_name, run_and_parse +) -> None: """Ensure record_xml_attribute and record_property drop values when outside of legacy family.""" - testdir.makeini( + pytester.makeini( """ [pytest] junit_family = xunit2 """ ) - testdir.makepyfile( + pytester.makepyfile( """ import pytest @@ -1246,13 +1317,15 @@ def test_record_fixtures_xunit2(testdir, fixture_name, run_and_parse): result.stdout.fnmatch_lines(expected_lines) -def test_random_report_log_xdist(testdir, monkeypatch, run_and_parse): +def test_random_report_log_xdist( + pytester: Pytester, monkeypatch: MonkeyPatch, run_and_parse +) -> None: """`xdist` calls pytest_runtest_logreport as they are executed by the workers, with nodes from several nodes overlapping, so junitxml must cope with that to produce correct reports (#1064).""" pytest.importorskip("xdist") monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) - testdir.makepyfile( + pytester.makepyfile( """ import pytest, time @pytest.mark.parametrize('i', list(range(30))) @@ -1271,8 +1344,8 @@ def test_random_report_log_xdist(testdir, monkeypatch, run_and_parse): @parametrize_families -def test_root_testsuites_tag(testdir, run_and_parse, xunit_family): - testdir.makepyfile( +def test_root_testsuites_tag(pytester: Pytester, run_and_parse, xunit_family) -> None: + pytester.makepyfile( """ def test_x(): pass @@ -1285,8 +1358,8 @@ def test_root_testsuites_tag(testdir, run_and_parse, xunit_family): assert suite_node.tag == "testsuite" -def test_runs_twice(testdir, run_and_parse): - f = testdir.makepyfile( +def test_runs_twice(pytester: Pytester, run_and_parse) -> None: + f = pytester.makepyfile( """ def test_pass(): pass @@ -1299,10 +1372,12 @@ def test_runs_twice(testdir, run_and_parse): assert first == second -def test_runs_twice_xdist(testdir, run_and_parse): +def test_runs_twice_xdist( + pytester: Pytester, monkeypatch: MonkeyPatch, run_and_parse +) -> None: pytest.importorskip("xdist") - testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") - f = testdir.makepyfile( + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") + f = pytester.makepyfile( """ def test_pass(): pass @@ -1315,9 +1390,9 @@ def test_runs_twice_xdist(testdir, run_and_parse): assert first == second -def test_fancy_items_regression(testdir, run_and_parse): +def test_fancy_items_regression(pytester: Pytester, run_and_parse) -> None: # issue 1259 - testdir.makeconftest( + pytester.makeconftest( """ import pytest class FunItem(pytest.Item): @@ -1341,7 +1416,7 @@ def test_fancy_items_regression(testdir, run_and_parse): """ ) - testdir.makepyfile( + pytester.makepyfile( """ def test_pass(): pass @@ -1368,8 +1443,8 @@ def test_fancy_items_regression(testdir, run_and_parse): @parametrize_families -def test_global_properties(testdir, xunit_family) -> None: - path = testdir.tmpdir.join("test_global_properties.xml") +def test_global_properties(pytester: Pytester, xunit_family) -> None: + path = pytester.path.joinpath("test_global_properties.xml") log = LogXML(str(path), None, family=xunit_family) class Report(BaseReport): @@ -1402,9 +1477,9 @@ def test_global_properties(testdir, xunit_family) -> None: assert actual == expected -def test_url_property(testdir) -> None: +def test_url_property(pytester: Pytester) -> None: test_url = "http://www.github.com/pytest-dev" - path = testdir.tmpdir.join("test_url_property.xml") + path = pytester.path.joinpath("test_url_property.xml") log = LogXML(str(path), None) class Report(BaseReport): @@ -1429,8 +1504,10 @@ def test_url_property(testdir) -> None: @parametrize_families -def test_record_testsuite_property(testdir, run_and_parse, xunit_family): - testdir.makepyfile( +def test_record_testsuite_property( + pytester: Pytester, run_and_parse, xunit_family +) -> None: + pytester.makepyfile( """ def test_func1(record_testsuite_property): record_testsuite_property("stats", "all good") @@ -1449,27 +1526,27 @@ def test_record_testsuite_property(testdir, run_and_parse, xunit_family): p2_node.assert_attr(name="stats", value="10") -def test_record_testsuite_property_junit_disabled(testdir): - testdir.makepyfile( +def test_record_testsuite_property_junit_disabled(pytester: Pytester) -> None: + pytester.makepyfile( """ def test_func1(record_testsuite_property): record_testsuite_property("stats", "all good") """ ) - result = testdir.runpytest() + result = pytester.runpytest() assert result.ret == 0 @pytest.mark.parametrize("junit", [True, False]) -def test_record_testsuite_property_type_checking(testdir, junit): - testdir.makepyfile( +def test_record_testsuite_property_type_checking(pytester: Pytester, junit) -> None: + pytester.makepyfile( """ def test_func1(record_testsuite_property): record_testsuite_property(1, 2) """ ) args = ("--junitxml=tests.xml",) if junit else () - result = testdir.runpytest(*args) + result = pytester.runpytest(*args) assert result.ret == 1 result.stdout.fnmatch_lines( ["*TypeError: name parameter needs to be a string, but int given"] @@ -1478,9 +1555,11 @@ def test_record_testsuite_property_type_checking(testdir, junit): @pytest.mark.parametrize("suite_name", ["my_suite", ""]) @parametrize_families -def test_set_suite_name(testdir, suite_name, run_and_parse, xunit_family): +def test_set_suite_name( + pytester: Pytester, suite_name, run_and_parse, xunit_family +) -> None: if suite_name: - testdir.makeini( + pytester.makeini( """ [pytest] junit_suite_name={suite_name} @@ -1492,7 +1571,7 @@ def test_set_suite_name(testdir, suite_name, run_and_parse, xunit_family): expected = suite_name else: expected = "pytest" - testdir.makepyfile( + pytester.makepyfile( """ import pytest @@ -1506,8 +1585,8 @@ def test_set_suite_name(testdir, suite_name, run_and_parse, xunit_family): node.assert_attr(name=expected) -def test_escaped_skipreason_issue3533(testdir, run_and_parse): - testdir.makepyfile( +def test_escaped_skipreason_issue3533(pytester: Pytester, run_and_parse) -> None: + pytester.makepyfile( """ import pytest @pytest.mark.skip(reason='1 <> 2') @@ -1524,9 +1603,9 @@ def test_escaped_skipreason_issue3533(testdir, run_and_parse): @parametrize_families def test_logging_passing_tests_disabled_does_not_log_test_output( - testdir, run_and_parse, xunit_family -): - testdir.makeini( + pytester: Pytester, run_and_parse, xunit_family +) -> None: + pytester.makeini( """ [pytest] junit_log_passing_tests=False @@ -1536,7 +1615,7 @@ def test_logging_passing_tests_disabled_does_not_log_test_output( family=xunit_family ) ) - testdir.makepyfile( + pytester.makepyfile( """ import pytest import logging @@ -1558,9 +1637,9 @@ def test_logging_passing_tests_disabled_does_not_log_test_output( @parametrize_families @pytest.mark.parametrize("junit_logging", ["no", "system-out", "system-err"]) def test_logging_passing_tests_disabled_logs_output_for_failing_test_issue5430( - testdir, junit_logging, run_and_parse, xunit_family -): - testdir.makeini( + pytester: Pytester, junit_logging, run_and_parse, xunit_family +) -> None: + pytester.makeini( """ [pytest] junit_log_passing_tests=False @@ -1569,7 +1648,7 @@ def test_logging_passing_tests_disabled_logs_output_for_failing_test_issue5430( family=xunit_family ) ) - testdir.makepyfile( + pytester.makepyfile( """ import pytest import logging diff --git a/testing/test_link_resolve.py b/testing/test_link_resolve.py index 7eaf41247..60a86ada3 100644 --- a/testing/test_link_resolve.py +++ b/testing/test_link_resolve.py @@ -3,15 +3,14 @@ import subprocess import sys import textwrap from contextlib import contextmanager +from pathlib import Path from string import ascii_lowercase -import py.path - -from _pytest import pytester +from _pytest.pytester import Pytester @contextmanager -def subst_path_windows(filename): +def subst_path_windows(filepath: Path): for c in ascii_lowercase[7:]: # Create a subst drive from H-Z. c += ":" if not os.path.exists(c): @@ -20,14 +19,14 @@ def subst_path_windows(filename): else: raise AssertionError("Unable to find suitable drive letter for subst.") - directory = filename.dirpath() - basename = filename.basename + directory = filepath.parent + basename = filepath.name args = ["subst", drive, str(directory)] subprocess.check_call(args) assert os.path.exists(drive) try: - filename = py.path.local(drive) / basename + filename = Path(drive, os.sep, basename) yield filename finally: args = ["subst", "/D", drive] @@ -35,9 +34,9 @@ def subst_path_windows(filename): @contextmanager -def subst_path_linux(filename): - directory = filename.dirpath() - basename = filename.basename +def subst_path_linux(filepath: Path): + directory = filepath.parent + basename = filepath.name target = directory / ".." / "sub2" os.symlink(str(directory), str(target), target_is_directory=True) @@ -49,11 +48,11 @@ def subst_path_linux(filename): pass -def test_link_resolve(testdir: pytester.Testdir) -> None: +def test_link_resolve(pytester: Pytester) -> None: """See: https://github.com/pytest-dev/pytest/issues/5965.""" - sub1 = testdir.mkpydir("sub1") - p = sub1.join("test_foo.py") - p.write( + sub1 = pytester.mkpydir("sub1") + p = sub1.joinpath("test_foo.py") + p.write_text( textwrap.dedent( """ import pytest @@ -68,7 +67,7 @@ def test_link_resolve(testdir: pytester.Testdir) -> None: subst = subst_path_windows with subst(p) as subst_p: - result = testdir.runpytest(str(subst_p), "-v") + result = pytester.runpytest(str(subst_p), "-v") # i.e.: Make sure that the error is reported as a relative path, not as a # resolved path. # See: https://github.com/pytest-dev/pytest/issues/5965 diff --git a/testing/test_main.py b/testing/test_main.py index f45607abc..2ed111895 100644 --- a/testing/test_main.py +++ b/testing/test_main.py @@ -10,7 +10,6 @@ from _pytest.config import UsageError from _pytest.main import resolve_collection_argument from _pytest.main import validate_basetemp from _pytest.pytester import Pytester -from _pytest.pytester import Testdir @pytest.mark.parametrize( @@ -21,9 +20,9 @@ from _pytest.pytester import Testdir pytest.param((False, SystemExit)), ), ) -def test_wrap_session_notify_exception(ret_exc, testdir): +def test_wrap_session_notify_exception(ret_exc, pytester: Pytester) -> None: returncode, exc = ret_exc - c1 = testdir.makeconftest( + c1 = pytester.makeconftest( """ import pytest @@ -38,7 +37,7 @@ def test_wrap_session_notify_exception(ret_exc, testdir): returncode=returncode, exc=exc.__name__ ) ) - result = testdir.runpytest() + result = pytester.runpytest() if returncode: assert result.ret == returncode else: @@ -65,9 +64,9 @@ def test_wrap_session_notify_exception(ret_exc, testdir): @pytest.mark.parametrize("returncode", (None, 42)) def test_wrap_session_exit_sessionfinish( - returncode: Optional[int], testdir: Testdir + returncode: Optional[int], pytester: Pytester ) -> None: - testdir.makeconftest( + pytester.makeconftest( """ import pytest def pytest_sessionfinish(): @@ -76,7 +75,7 @@ def test_wrap_session_exit_sessionfinish( returncode=returncode ) ) - result = testdir.runpytest() + result = pytester.runpytest() if returncode: assert result.ret == returncode else: @@ -101,8 +100,8 @@ def test_validate_basetemp_fails(tmp_path, basetemp, monkeypatch): validate_basetemp(basetemp) -def test_validate_basetemp_integration(testdir): - result = testdir.runpytest("--basetemp=.") +def test_validate_basetemp_integration(pytester: Pytester) -> None: + result = pytester.runpytest("--basetemp=.") result.stderr.fnmatch_lines("*basetemp must not be*") @@ -203,14 +202,14 @@ class TestResolveCollectionArgument: ) == (Path(os.path.abspath("src")), []) -def test_module_full_path_without_drive(testdir): +def test_module_full_path_without_drive(pytester: Pytester) -> None: """Collect and run test using full path except for the drive letter (#7628). Passing a full path without a drive letter would trigger a bug in py.path.local where it would keep the full path without the drive letter around, instead of resolving to the full path, resulting in fixtures node ids not matching against test node ids correctly. """ - testdir.makepyfile( + pytester.makepyfile( **{ "project/conftest.py": """ import pytest @@ -220,7 +219,7 @@ def test_module_full_path_without_drive(testdir): } ) - testdir.makepyfile( + pytester.makepyfile( **{ "project/tests/dummy_test.py": """ def test(fix): @@ -228,12 +227,12 @@ def test_module_full_path_without_drive(testdir): """ } ) - fn = testdir.tmpdir.join("project/tests/dummy_test.py") - assert fn.isfile() + fn = pytester.path.joinpath("project/tests/dummy_test.py") + assert fn.is_file() drive, path = os.path.splitdrive(str(fn)) - result = testdir.runpytest(path, "-v") + result = pytester.runpytest(path, "-v") result.stdout.fnmatch_lines( [ os.path.join("project", "tests", "dummy_test.py") + "::test PASSED *", diff --git a/testing/test_parseopt.py b/testing/test_parseopt.py index a124009c4..c33337b67 100644 --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -315,7 +315,7 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None: shlex.quote(sys.executable) ) ) - # alternative would be extended Testdir.{run(),_run(),popen()} to be able + # alternative would be extended Pytester.{run(),_run(),popen()} to be able # to handle a keyword argument env that replaces os.environ in popen or # extends the copy, advantage: could not forget to restore monkeypatch.setenv("_ARGCOMPLETE", "1") diff --git a/testing/test_pytester.py b/testing/test_pytester.py index f2e8dd5a3..a9ba1a046 100644 --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -2,26 +2,26 @@ import os import subprocess import sys import time +from pathlib import Path +from types import ModuleType from typing import List -import py.path - -import _pytest.pytester as pytester +import _pytest.pytester as pytester_mod import pytest from _pytest.config import ExitCode from _pytest.config import PytestPluginManager +from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import CwdSnapshot from _pytest.pytester import HookRecorder from _pytest.pytester import LineMatcher from _pytest.pytester import Pytester from _pytest.pytester import SysModulesSnapshot from _pytest.pytester import SysPathsSnapshot -from _pytest.pytester import Testdir -def test_make_hook_recorder(testdir) -> None: - item = testdir.getitem("def test_func(): pass") - recorder = testdir.make_hook_recorder(item.config.pluginmanager) +def test_make_hook_recorder(pytester: Pytester) -> None: + item = pytester.getitem("def test_func(): pass") + recorder = pytester.make_hook_recorder(item.config.pluginmanager) assert not recorder.getfailures() # (The silly condition is to fool mypy that the code below this is reachable) @@ -35,11 +35,11 @@ def test_make_hook_recorder(testdir) -> None: skipped = False when = "call" - recorder.hook.pytest_runtest_logreport(report=rep) + recorder.hook.pytest_runtest_logreport(report=rep) # type: ignore[attr-defined] failures = recorder.getfailures() - assert failures == [rep] + assert failures == [rep] # type: ignore[comparison-overlap] failures = recorder.getfailures() - assert failures == [rep] + assert failures == [rep] # type: ignore[comparison-overlap] class rep2: excinfo = None @@ -50,14 +50,14 @@ def test_make_hook_recorder(testdir) -> None: rep2.passed = False rep2.skipped = True - recorder.hook.pytest_runtest_logreport(report=rep2) + recorder.hook.pytest_runtest_logreport(report=rep2) # type: ignore[attr-defined] - modcol = testdir.getmodulecol("") + modcol = pytester.getmodulecol("") rep3 = modcol.config.hook.pytest_make_collect_report(collector=modcol) rep3.passed = False rep3.failed = True rep3.skipped = False - recorder.hook.pytest_collectreport(report=rep3) + recorder.hook.pytest_collectreport(report=rep3) # type: ignore[attr-defined] passed, skipped, failed = recorder.listoutcomes() assert not passed and skipped and failed @@ -68,55 +68,55 @@ def test_make_hook_recorder(testdir) -> None: assert numfailed == 1 assert len(recorder.getfailedcollections()) == 1 - recorder.unregister() + recorder.unregister() # type: ignore[attr-defined] recorder.clear() - recorder.hook.pytest_runtest_logreport(report=rep3) + recorder.hook.pytest_runtest_logreport(report=rep3) # type: ignore[attr-defined] pytest.raises(ValueError, recorder.getfailures) -def test_parseconfig(testdir) -> None: - config1 = testdir.parseconfig() - config2 = testdir.parseconfig() +def test_parseconfig(pytester: Pytester) -> None: + config1 = pytester.parseconfig() + config2 = pytester.parseconfig() assert config2 is not config1 -def test_testdir_runs_with_plugin(testdir) -> None: - testdir.makepyfile( +def test_pytester_runs_with_plugin(pytester: Pytester) -> None: + pytester.makepyfile( """ pytest_plugins = "pytester" - def test_hello(testdir): + def test_hello(pytester): assert 1 """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.assert_outcomes(passed=1) -def test_testdir_with_doctest(testdir): - """Check that testdir can be used within doctests. +def test_pytester_with_doctest(pytester: Pytester): + """Check that pytester can be used within doctests. It used to use `request.function`, which is `None` with doctests.""" - testdir.makepyfile( + pytester.makepyfile( **{ "sub/t-doctest.py": """ ''' >>> import os - >>> testdir = getfixture("testdir") - >>> str(testdir.makepyfile("content")).replace(os.sep, '/') + >>> pytester = getfixture("pytester") + >>> str(pytester.makepyfile("content")).replace(os.sep, '/') '.../basetemp/sub.t-doctest0/sub.py' ''' """, "sub/__init__.py": "", } ) - result = testdir.runpytest( + result = pytester.runpytest( "-p", "pytester", "--doctest-modules", "sub/t-doctest.py" ) assert result.ret == 0 -def test_runresult_assertion_on_xfail(testdir) -> None: - testdir.makepyfile( +def test_runresult_assertion_on_xfail(pytester: Pytester) -> None: + pytester.makepyfile( """ import pytest @@ -127,13 +127,13 @@ def test_runresult_assertion_on_xfail(testdir) -> None: assert False """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.assert_outcomes(xfailed=1) assert result.ret == 0 -def test_runresult_assertion_on_xpassed(testdir) -> None: - testdir.makepyfile( +def test_runresult_assertion_on_xpassed(pytester: Pytester) -> None: + pytester.makepyfile( """ import pytest @@ -144,13 +144,13 @@ def test_runresult_assertion_on_xpassed(testdir) -> None: assert True """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.assert_outcomes(xpassed=1) assert result.ret == 0 -def test_xpassed_with_strict_is_considered_a_failure(testdir) -> None: - testdir.makepyfile( +def test_xpassed_with_strict_is_considered_a_failure(pytester: Pytester) -> None: + pytester.makepyfile( """ import pytest @@ -161,7 +161,7 @@ def test_xpassed_with_strict_is_considered_a_failure(testdir) -> None: assert True """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.assert_outcomes(failed=1) assert result.ret != 0 @@ -202,28 +202,28 @@ def test_hookrecorder_basic(holder) -> None: assert call._name == "pytest_xyz_noarg" -def test_makepyfile_unicode(testdir) -> None: - testdir.makepyfile(chr(0xFFFD)) +def test_makepyfile_unicode(pytester: Pytester) -> None: + pytester.makepyfile(chr(0xFFFD)) -def test_makepyfile_utf8(testdir) -> None: +def test_makepyfile_utf8(pytester: Pytester) -> None: """Ensure makepyfile accepts utf-8 bytes as input (#2738)""" utf8_contents = """ def setup_function(function): mixed_encoding = 'São Paulo' """.encode() - p = testdir.makepyfile(utf8_contents) - assert "mixed_encoding = 'São Paulo'".encode() in p.read("rb") + p = pytester.makepyfile(utf8_contents) + assert "mixed_encoding = 'São Paulo'".encode() in p.read_bytes() class TestInlineRunModulesCleanup: - def test_inline_run_test_module_not_cleaned_up(self, testdir) -> None: - test_mod = testdir.makepyfile("def test_foo(): assert True") - result = testdir.inline_run(str(test_mod)) + def test_inline_run_test_module_not_cleaned_up(self, pytester: Pytester) -> None: + test_mod = pytester.makepyfile("def test_foo(): assert True") + result = pytester.inline_run(str(test_mod)) assert result.ret == ExitCode.OK # rewrite module, now test should fail if module was re-imported - test_mod.write("def test_foo(): assert False") - result2 = testdir.inline_run(str(test_mod)) + test_mod.write_text("def test_foo(): assert False") + result2 = pytester.inline_run(str(test_mod)) assert result2.ret == ExitCode.TESTS_FAILED def spy_factory(self): @@ -243,20 +243,20 @@ class TestInlineRunModulesCleanup: return SysModulesSnapshotSpy def test_inline_run_taking_and_restoring_a_sys_modules_snapshot( - self, testdir, monkeypatch + self, pytester: Pytester, monkeypatch: MonkeyPatch ) -> None: spy_factory = self.spy_factory() - monkeypatch.setattr(pytester, "SysModulesSnapshot", spy_factory) - testdir.syspathinsert() + monkeypatch.setattr(pytester_mod, "SysModulesSnapshot", spy_factory) + pytester.syspathinsert() original = dict(sys.modules) - testdir.makepyfile(import1="# you son of a silly person") - testdir.makepyfile(import2="# my hovercraft is full of eels") - test_mod = testdir.makepyfile( + pytester.makepyfile(import1="# you son of a silly person") + pytester.makepyfile(import2="# my hovercraft is full of eels") + test_mod = pytester.makepyfile( """ import import1 def test_foo(): import import2""" ) - testdir.inline_run(str(test_mod)) + pytester.inline_run(str(test_mod)) assert len(spy_factory.instances) == 1 spy = spy_factory.instances[0] assert spy._spy_restore_count == 1 @@ -264,55 +264,57 @@ class TestInlineRunModulesCleanup: assert all(sys.modules[x] is original[x] for x in sys.modules) def test_inline_run_sys_modules_snapshot_restore_preserving_modules( - self, testdir, monkeypatch + self, pytester: Pytester, monkeypatch: MonkeyPatch ) -> None: spy_factory = self.spy_factory() - monkeypatch.setattr(pytester, "SysModulesSnapshot", spy_factory) - test_mod = testdir.makepyfile("def test_foo(): pass") - testdir.inline_run(str(test_mod)) + monkeypatch.setattr(pytester_mod, "SysModulesSnapshot", spy_factory) + test_mod = pytester.makepyfile("def test_foo(): pass") + pytester.inline_run(str(test_mod)) spy = spy_factory.instances[0] assert not spy._spy_preserve("black_knight") assert spy._spy_preserve("zope") assert spy._spy_preserve("zope.interface") assert spy._spy_preserve("zopelicious") - def test_external_test_module_imports_not_cleaned_up(self, testdir) -> None: - testdir.syspathinsert() - testdir.makepyfile(imported="data = 'you son of a silly person'") + def test_external_test_module_imports_not_cleaned_up( + self, pytester: Pytester + ) -> None: + pytester.syspathinsert() + pytester.makepyfile(imported="data = 'you son of a silly person'") import imported - test_mod = testdir.makepyfile( + test_mod = pytester.makepyfile( """ def test_foo(): import imported imported.data = 42""" ) - testdir.inline_run(str(test_mod)) + pytester.inline_run(str(test_mod)) assert imported.data == 42 -def test_assert_outcomes_after_pytest_error(testdir) -> None: - testdir.makepyfile("def test_foo(): assert True") +def test_assert_outcomes_after_pytest_error(pytester: Pytester) -> None: + pytester.makepyfile("def test_foo(): assert True") - result = testdir.runpytest("--unexpected-argument") + result = pytester.runpytest("--unexpected-argument") with pytest.raises(ValueError, match="Pytest terminal summary report not found"): result.assert_outcomes(passed=0) -def test_cwd_snapshot(testdir: Testdir) -> None: - tmpdir = testdir.tmpdir - foo = tmpdir.ensure("foo", dir=1) - bar = tmpdir.ensure("bar", dir=1) - foo.chdir() +def test_cwd_snapshot(pytester: Pytester) -> None: + foo = pytester.mkdir("foo") + bar = pytester.mkdir("bar") + os.chdir(foo) snapshot = CwdSnapshot() - bar.chdir() - assert py.path.local() == bar + os.chdir(bar) + assert Path().absolute() == bar snapshot.restore() - assert py.path.local() == foo + assert Path().absolute() == foo class TestSysModulesSnapshot: key = "my-test-module" + mod = ModuleType("something") def test_remove_added(self) -> None: original = dict(sys.modules) @@ -323,9 +325,9 @@ class TestSysModulesSnapshot: snapshot.restore() assert sys.modules == original - def test_add_removed(self, monkeypatch) -> None: + def test_add_removed(self, monkeypatch: MonkeyPatch) -> None: assert self.key not in sys.modules - monkeypatch.setitem(sys.modules, self.key, "something") + monkeypatch.setitem(sys.modules, self.key, self.mod) assert self.key in sys.modules original = dict(sys.modules) snapshot = SysModulesSnapshot() @@ -334,9 +336,9 @@ class TestSysModulesSnapshot: snapshot.restore() assert sys.modules == original - def test_restore_reloaded(self, monkeypatch) -> None: + def test_restore_reloaded(self, monkeypatch: MonkeyPatch) -> None: assert self.key not in sys.modules - monkeypatch.setitem(sys.modules, self.key, "something") + monkeypatch.setitem(sys.modules, self.key, self.mod) assert self.key in sys.modules original = dict(sys.modules) snapshot = SysModulesSnapshot() @@ -344,11 +346,12 @@ class TestSysModulesSnapshot: snapshot.restore() assert sys.modules == original - def test_preserve_modules(self, monkeypatch) -> None: + def test_preserve_modules(self, monkeypatch: MonkeyPatch) -> None: key = [self.key + str(i) for i in range(3)] assert not any(k in sys.modules for k in key) for i, k in enumerate(key): - monkeypatch.setitem(sys.modules, k, "something" + str(i)) + mod = ModuleType("something" + str(i)) + monkeypatch.setitem(sys.modules, k, mod) original = dict(sys.modules) def preserve(name): @@ -361,7 +364,7 @@ class TestSysModulesSnapshot: snapshot.restore() assert sys.modules == original - def test_preserve_container(self, monkeypatch) -> None: + def test_preserve_container(self, monkeypatch: MonkeyPatch) -> None: original = dict(sys.modules) assert self.key not in original replacement = dict(sys.modules) @@ -381,7 +384,7 @@ class TestSysPathsSnapshot: def path(n: int) -> str: return "my-dirty-little-secret-" + str(n) - def test_restore(self, monkeypatch, path_type) -> None: + def test_restore(self, monkeypatch: MonkeyPatch, path_type) -> None: other_path_type = self.other_path[path_type] for i in range(10): assert self.path(i) not in getattr(sys, path_type) @@ -404,7 +407,7 @@ class TestSysPathsSnapshot: assert getattr(sys, path_type) == original assert getattr(sys, other_path_type) == original_other - def test_preserve_container(self, monkeypatch, path_type) -> None: + def test_preserve_container(self, monkeypatch: MonkeyPatch, path_type) -> None: other_path_type = self.other_path[path_type] original_data = list(getattr(sys, path_type)) original_other = getattr(sys, other_path_type) @@ -419,49 +422,47 @@ class TestSysPathsSnapshot: assert getattr(sys, other_path_type) == original_other_data -def test_testdir_subprocess(testdir) -> None: - testfile = testdir.makepyfile("def test_one(): pass") - assert testdir.runpytest_subprocess(testfile).ret == 0 +def test_pytester_subprocess(pytester: Pytester) -> None: + testfile = pytester.makepyfile("def test_one(): pass") + assert pytester.runpytest_subprocess(testfile).ret == 0 -def test_testdir_subprocess_via_runpytest_arg(testdir) -> None: - testfile = testdir.makepyfile( +def test_pytester_subprocess_via_runpytest_arg(pytester: Pytester) -> None: + testfile = pytester.makepyfile( """ - def test_testdir_subprocess(testdir): + def test_pytester_subprocess(pytester): import os - testfile = testdir.makepyfile( + testfile = pytester.makepyfile( \""" import os def test_one(): assert {} != os.getpid() \""".format(os.getpid()) ) - assert testdir.runpytest(testfile).ret == 0 + assert pytester.runpytest(testfile).ret == 0 """ ) - result = testdir.runpytest_subprocess( - "-p", "pytester", "--runpytest", "subprocess", testfile - ) + result = pytester.runpytest("-p", "pytester", "--runpytest", "subprocess", testfile) assert result.ret == 0 -def test_unicode_args(testdir) -> None: - result = testdir.runpytest("-k", "אבג") +def test_unicode_args(pytester: Pytester) -> None: + result = pytester.runpytest("-k", "אבג") assert result.ret == ExitCode.NO_TESTS_COLLECTED -def test_testdir_run_no_timeout(testdir) -> None: - testfile = testdir.makepyfile("def test_no_timeout(): pass") - assert testdir.runpytest_subprocess(testfile).ret == ExitCode.OK +def test_pytester_run_no_timeout(pytester: Pytester) -> None: + testfile = pytester.makepyfile("def test_no_timeout(): pass") + assert pytester.runpytest_subprocess(testfile).ret == ExitCode.OK -def test_testdir_run_with_timeout(testdir) -> None: - testfile = testdir.makepyfile("def test_no_timeout(): pass") +def test_pytester_run_with_timeout(pytester: Pytester) -> None: + testfile = pytester.makepyfile("def test_no_timeout(): pass") timeout = 120 start = time.time() - result = testdir.runpytest_subprocess(testfile, timeout=timeout) + result = pytester.runpytest_subprocess(testfile, timeout=timeout) end = time.time() duration = end - start @@ -469,16 +470,16 @@ def test_testdir_run_with_timeout(testdir) -> None: assert duration < timeout -def test_testdir_run_timeout_expires(testdir) -> None: - testfile = testdir.makepyfile( +def test_pytester_run_timeout_expires(pytester: Pytester) -> None: + testfile = pytester.makepyfile( """ import time def test_timeout(): time.sleep(10)""" ) - with pytest.raises(testdir.TimeoutExpired): - testdir.runpytest_subprocess(testfile, timeout=1) + with pytest.raises(pytester.TimeoutExpired): + pytester.runpytest_subprocess(testfile, timeout=1) def test_linematcher_with_nonlist() -> None: @@ -533,7 +534,7 @@ def test_linematcher_match_failure() -> None: ] -def test_linematcher_consecutive(): +def test_linematcher_consecutive() -> None: lm = LineMatcher(["1", "", "2"]) with pytest.raises(pytest.fail.Exception) as excinfo: lm.fnmatch_lines(["1", "2"], consecutive=True) @@ -554,7 +555,7 @@ def test_linematcher_consecutive(): @pytest.mark.parametrize("function", ["no_fnmatch_line", "no_re_match_line"]) -def test_linematcher_no_matching(function) -> None: +def test_linematcher_no_matching(function: str) -> None: if function == "no_fnmatch_line": good_pattern = "*.py OK*" bad_pattern = "*X.py OK*" @@ -615,7 +616,7 @@ def test_linematcher_string_api() -> None: assert str(lm) == "foo\nbar" -def test_pytester_addopts_before_testdir(request, monkeypatch) -> None: +def test_pytester_addopts_before_testdir(request, monkeypatch: MonkeyPatch) -> None: orig = os.environ.get("PYTEST_ADDOPTS", None) monkeypatch.setenv("PYTEST_ADDOPTS", "--orig-unused") testdir = request.getfixturevalue("testdir") @@ -626,9 +627,9 @@ def test_pytester_addopts_before_testdir(request, monkeypatch) -> None: assert os.environ.get("PYTEST_ADDOPTS") == orig -def test_run_stdin(testdir) -> None: - with pytest.raises(testdir.TimeoutExpired): - testdir.run( +def test_run_stdin(pytester: Pytester) -> None: + with pytest.raises(pytester.TimeoutExpired): + pytester.run( sys.executable, "-c", "import sys, time; time.sleep(1); print(sys.stdin.read())", @@ -636,8 +637,8 @@ def test_run_stdin(testdir) -> None: timeout=0.1, ) - with pytest.raises(testdir.TimeoutExpired): - result = testdir.run( + with pytest.raises(pytester.TimeoutExpired): + result = pytester.run( sys.executable, "-c", "import sys, time; time.sleep(1); print(sys.stdin.read())", @@ -645,7 +646,7 @@ def test_run_stdin(testdir) -> None: timeout=0.1, ) - result = testdir.run( + result = pytester.run( sys.executable, "-c", "import sys; print(sys.stdin.read())", @@ -656,8 +657,8 @@ def test_run_stdin(testdir) -> None: assert result.ret == 0 -def test_popen_stdin_pipe(testdir) -> None: - proc = testdir.popen( +def test_popen_stdin_pipe(pytester: Pytester) -> None: + proc = pytester.popen( [sys.executable, "-c", "import sys; print(sys.stdin.read())"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -670,8 +671,8 @@ def test_popen_stdin_pipe(testdir) -> None: assert proc.returncode == 0 -def test_popen_stdin_bytes(testdir) -> None: - proc = testdir.popen( +def test_popen_stdin_bytes(pytester: Pytester) -> None: + proc = pytester.popen( [sys.executable, "-c", "import sys; print(sys.stdin.read())"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -683,18 +684,18 @@ def test_popen_stdin_bytes(testdir) -> None: assert proc.returncode == 0 -def test_popen_default_stdin_stderr_and_stdin_None(testdir) -> None: +def test_popen_default_stdin_stderr_and_stdin_None(pytester: Pytester) -> None: # stdout, stderr default to pipes, # stdin can be None to not close the pipe, avoiding # "ValueError: flush of closed file" with `communicate()`. # # Wraps the test to make it not hang when run with "-s". - p1 = testdir.makepyfile( + p1 = pytester.makepyfile( ''' import sys - def test_inner(testdir): - p1 = testdir.makepyfile( + def test_inner(pytester): + p1 = pytester.makepyfile( """ import sys print(sys.stdin.read()) # empty @@ -702,14 +703,14 @@ def test_popen_default_stdin_stderr_and_stdin_None(testdir) -> None: sys.stderr.write('stderr') """ ) - proc = testdir.popen([sys.executable, str(p1)], stdin=None) + proc = pytester.popen([sys.executable, str(p1)], stdin=None) stdout, stderr = proc.communicate(b"ignored") assert stdout.splitlines() == [b"", b"stdout"] assert stderr.splitlines() == [b"stderr"] assert proc.returncode == 0 ''' ) - result = testdir.runpytest("-p", "pytester", str(p1)) + result = pytester.runpytest("-p", "pytester", str(p1)) assert result.ret == 0 @@ -740,22 +741,22 @@ def test_run_result_repr() -> None: errlines = ["some", "nasty", "errors", "happened"] # known exit code - r = pytester.RunResult(1, outlines, errlines, duration=0.5) + r = pytester_mod.RunResult(1, outlines, errlines, duration=0.5) assert ( repr(r) == "" ) # unknown exit code: just the number - r = pytester.RunResult(99, outlines, errlines, duration=0.5) + r = pytester_mod.RunResult(99, outlines, errlines, duration=0.5) assert ( repr(r) == "" ) -def test_testdir_outcomes_with_multiple_errors(testdir): - p1 = testdir.makepyfile( +def test_pytester_outcomes_with_multiple_errors(pytester: Pytester) -> None: + p1 = pytester.makepyfile( """ import pytest @@ -770,7 +771,7 @@ def test_testdir_outcomes_with_multiple_errors(testdir): pass """ ) - result = testdir.runpytest(str(p1)) + result = pytester.runpytest(str(p1)) result.assert_outcomes(errors=2) assert result.parseoutcomes() == {"errors": 2} @@ -784,7 +785,7 @@ def test_parse_summary_line_always_plural(): "======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====", "done.", ] - assert pytester.RunResult.parse_summary_nouns(lines) == { + assert pytester_mod.RunResult.parse_summary_nouns(lines) == { "errors": 1, "failed": 1, "passed": 1, @@ -797,7 +798,7 @@ def test_parse_summary_line_always_plural(): "======= 1 failed, 1 passed, 2 warnings, 2 errors in 0.13s ====", "done.", ] - assert pytester.RunResult.parse_summary_nouns(lines) == { + assert pytester_mod.RunResult.parse_summary_nouns(lines) == { "errors": 2, "failed": 1, "passed": 1, @@ -805,10 +806,10 @@ def test_parse_summary_line_always_plural(): } -def test_makefile_joins_absolute_path(testdir: Testdir) -> None: - absfile = testdir.tmpdir / "absfile" - p1 = testdir.makepyfile(**{str(absfile): ""}) - assert str(p1) == str(testdir.tmpdir / "absfile.py") +def test_makefile_joins_absolute_path(pytester: Pytester) -> None: + absfile = pytester.path / "absfile" + p1 = pytester.makepyfile(**{str(absfile): ""}) + assert str(p1) == str(pytester.path / "absfile.py") def test_testtmproot(testdir): diff --git a/testing/test_unittest.py b/testing/test_unittest.py index 8b00cb826..feee09286 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -4,11 +4,12 @@ from typing import List import pytest from _pytest.config import ExitCode -from _pytest.pytester import Testdir +from _pytest.monkeypatch import MonkeyPatch +from _pytest.pytester import Pytester -def test_simple_unittest(testdir): - testpath = testdir.makepyfile( +def test_simple_unittest(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -18,13 +19,13 @@ def test_simple_unittest(testdir): self.assertEqual('foo', 'bar') """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) assert reprec.matchreport("testpassing").passed assert reprec.matchreport("test_failing").failed -def test_runTest_method(testdir): - testdir.makepyfile( +def test_runTest_method(pytester: Pytester) -> None: + pytester.makepyfile( """ import unittest class MyTestCaseWithRunTest(unittest.TestCase): @@ -37,7 +38,7 @@ def test_runTest_method(testdir): pass """ ) - result = testdir.runpytest("-v") + result = pytester.runpytest("-v") result.stdout.fnmatch_lines( """ *MyTestCaseWithRunTest::runTest* @@ -47,8 +48,8 @@ def test_runTest_method(testdir): ) -def test_isclasscheck_issue53(testdir): - testpath = testdir.makepyfile( +def test_isclasscheck_issue53(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class _E(object): @@ -57,12 +58,12 @@ def test_isclasscheck_issue53(testdir): E = _E() """ ) - result = testdir.runpytest(testpath) + result = pytester.runpytest(testpath) assert result.ret == ExitCode.NO_TESTS_COLLECTED -def test_setup(testdir): - testpath = testdir.makepyfile( +def test_setup(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -78,14 +79,14 @@ def test_setup(testdir): """ ) - reprec = testdir.inline_run("-s", testpath) + reprec = pytester.inline_run("-s", testpath) assert reprec.matchreport("test_both", when="call").passed rep = reprec.matchreport("test_both", when="teardown") assert rep.failed and "42" in str(rep.longrepr) -def test_setUpModule(testdir): - testpath = testdir.makepyfile( +def test_setUpModule(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ values = [] @@ -102,12 +103,12 @@ def test_setUpModule(testdir): assert values == [1] """ ) - result = testdir.runpytest(testpath) + result = pytester.runpytest(testpath) result.stdout.fnmatch_lines(["*2 passed*"]) -def test_setUpModule_failing_no_teardown(testdir): - testpath = testdir.makepyfile( +def test_setUpModule_failing_no_teardown(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ values = [] @@ -121,14 +122,14 @@ def test_setUpModule_failing_no_teardown(testdir): pass """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) reprec.assertoutcome(passed=0, failed=1) call = reprec.getcalls("pytest_runtest_setup")[0] assert not call.item.module.values -def test_new_instances(testdir): - testpath = testdir.makepyfile( +def test_new_instances(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -138,13 +139,13 @@ def test_new_instances(testdir): assert not hasattr(self, 'x') """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) reprec.assertoutcome(passed=2) -def test_function_item_obj_is_instance(testdir): +def test_function_item_obj_is_instance(pytester: Pytester) -> None: """item.obj should be a bound method on unittest.TestCase function items (#5390).""" - testdir.makeconftest( + pytester.makeconftest( """ def pytest_runtest_makereport(item, call): if call.when == 'call': @@ -152,7 +153,7 @@ def test_function_item_obj_is_instance(testdir): assert isinstance(item.obj.__self__, class_) """ ) - testdir.makepyfile( + pytester.makepyfile( """ import unittest @@ -161,12 +162,12 @@ def test_function_item_obj_is_instance(testdir): pass """ ) - result = testdir.runpytest_inprocess() + result = pytester.runpytest_inprocess() result.stdout.fnmatch_lines(["* 1 passed in*"]) -def test_teardown(testdir): - testpath = testdir.makepyfile( +def test_teardown(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -180,14 +181,14 @@ def test_teardown(testdir): self.assertEqual(MyTestCase.values, [None]) """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() assert failed == 0, failed assert passed == 2 assert passed + skipped + failed == 2 -def test_teardown_issue1649(testdir): +def test_teardown_issue1649(pytester: Pytester) -> None: """ Are TestCase objects cleaned up? Often unittest TestCase objects set attributes that are large and expensive during setUp. @@ -195,7 +196,7 @@ def test_teardown_issue1649(testdir): The TestCase will not be cleaned up if the test fails, because it would then exist in the stackframe. """ - testpath = testdir.makepyfile( + testpath = pytester.makepyfile( """ import unittest class TestCaseObjectsShouldBeCleanedUp(unittest.TestCase): @@ -206,14 +207,14 @@ def test_teardown_issue1649(testdir): """ ) - testdir.inline_run("-s", testpath) + pytester.inline_run("-s", testpath) gc.collect() for obj in gc.get_objects(): assert type(obj).__name__ != "TestCaseObjectsShouldBeCleanedUp" -def test_unittest_skip_issue148(testdir): - testpath = testdir.makepyfile( +def test_unittest_skip_issue148(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest @@ -229,12 +230,12 @@ def test_unittest_skip_issue148(testdir): xxx """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) reprec.assertoutcome(skipped=1) -def test_method_and_teardown_failing_reporting(testdir): - testdir.makepyfile( +def test_method_and_teardown_failing_reporting(pytester: Pytester) -> None: + pytester.makepyfile( """ import unittest class TC(unittest.TestCase): @@ -244,7 +245,7 @@ def test_method_and_teardown_failing_reporting(testdir): assert False, "down2" """ ) - result = testdir.runpytest("-s") + result = pytester.runpytest("-s") assert result.ret == 1 result.stdout.fnmatch_lines( [ @@ -257,8 +258,8 @@ def test_method_and_teardown_failing_reporting(testdir): ) -def test_setup_failure_is_shown(testdir): - testdir.makepyfile( +def test_setup_failure_is_shown(pytester: Pytester) -> None: + pytester.makepyfile( """ import unittest import pytest @@ -270,14 +271,14 @@ def test_setup_failure_is_shown(testdir): xyz """ ) - result = testdir.runpytest("-s") + result = pytester.runpytest("-s") assert result.ret == 1 result.stdout.fnmatch_lines(["*setUp*", "*assert 0*down1*", "*1 failed*"]) result.stdout.no_fnmatch_line("*never42*") -def test_setup_setUpClass(testdir): - testpath = testdir.makepyfile( +def test_setup_setUpClass(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest import pytest @@ -297,12 +298,12 @@ def test_setup_setUpClass(testdir): assert MyTestCase.x == 0 """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) reprec.assertoutcome(passed=3) -def test_setup_class(testdir): - testpath = testdir.makepyfile( +def test_setup_class(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest import pytest @@ -320,13 +321,13 @@ def test_setup_class(testdir): assert MyTestCase.x == 0 """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) reprec.assertoutcome(passed=3) @pytest.mark.parametrize("type", ["Error", "Failure"]) -def test_testcase_adderrorandfailure_defers(testdir, type): - testdir.makepyfile( +def test_testcase_adderrorandfailure_defers(pytester: Pytester, type: str) -> None: + pytester.makepyfile( """ from unittest import TestCase import pytest @@ -344,13 +345,13 @@ def test_testcase_adderrorandfailure_defers(testdir, type): """ % (type, type) ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.no_fnmatch_line("*should not raise*") @pytest.mark.parametrize("type", ["Error", "Failure"]) -def test_testcase_custom_exception_info(testdir, type): - testdir.makepyfile( +def test_testcase_custom_exception_info(pytester: Pytester, type: str) -> None: + pytester.makepyfile( """ from unittest import TestCase import py, pytest @@ -375,7 +376,7 @@ def test_testcase_custom_exception_info(testdir, type): """ % locals() ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "NOTE: Incompatible Exception Representation*", @@ -385,8 +386,10 @@ def test_testcase_custom_exception_info(testdir, type): ) -def test_testcase_totally_incompatible_exception_info(testdir): - (item,) = testdir.getitems( +def test_testcase_totally_incompatible_exception_info(pytester: Pytester) -> None: + import _pytest.unittest + + (item,) = pytester.getitems( """ from unittest import TestCase class MyTestCase(TestCase): @@ -394,13 +397,15 @@ def test_testcase_totally_incompatible_exception_info(testdir): pass """ ) - item.addError(None, 42) - excinfo = item._excinfo.pop(0) - assert "ERROR: Unknown Incompatible" in str(excinfo.getrepr()) + assert isinstance(item, _pytest.unittest.TestCaseFunction) + item.addError(None, 42) # type: ignore[arg-type] + excinfo = item._excinfo + assert excinfo is not None + assert "ERROR: Unknown Incompatible" in str(excinfo.pop(0).getrepr()) -def test_module_level_pytestmark(testdir): - testpath = testdir.makepyfile( +def test_module_level_pytestmark(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest import pytest @@ -410,7 +415,7 @@ def test_module_level_pytestmark(testdir): assert 0 """ ) - reprec = testdir.inline_run(testpath, "-s") + reprec = pytester.inline_run(testpath, "-s") reprec.assertoutcome(skipped=1) @@ -421,8 +426,8 @@ class TestTrialUnittest: # https://twistedmatrix.com/trac/ticket/9227 cls.ignore_unclosed_socket_warning = ("-W", "always") - def test_trial_testcase_runtest_not_collected(self, testdir): - testdir.makepyfile( + def test_trial_testcase_runtest_not_collected(self, pytester: Pytester) -> None: + pytester.makepyfile( """ from twisted.trial.unittest import TestCase @@ -431,9 +436,9 @@ class TestTrialUnittest: pass """ ) - reprec = testdir.inline_run(*self.ignore_unclosed_socket_warning) + reprec = pytester.inline_run(*self.ignore_unclosed_socket_warning) reprec.assertoutcome(passed=1) - testdir.makepyfile( + pytester.makepyfile( """ from twisted.trial.unittest import TestCase @@ -442,11 +447,11 @@ class TestTrialUnittest: pass """ ) - reprec = testdir.inline_run(*self.ignore_unclosed_socket_warning) + reprec = pytester.inline_run(*self.ignore_unclosed_socket_warning) reprec.assertoutcome(passed=1) - def test_trial_exceptions_with_skips(self, testdir): - testdir.makepyfile( + def test_trial_exceptions_with_skips(self, pytester: Pytester) -> None: + pytester.makepyfile( """ from twisted.trial import unittest import pytest @@ -480,7 +485,7 @@ class TestTrialUnittest: pass """ ) - result = testdir.runpytest("-rxs", *self.ignore_unclosed_socket_warning) + result = pytester.runpytest("-rxs", *self.ignore_unclosed_socket_warning) result.stdout.fnmatch_lines_random( [ "*XFAIL*test_trial_todo*", @@ -495,8 +500,8 @@ class TestTrialUnittest: ) assert result.ret == 1 - def test_trial_error(self, testdir): - testdir.makepyfile( + def test_trial_error(self, pytester: Pytester) -> None: + pytester.makepyfile( """ from twisted.trial.unittest import TestCase from twisted.internet.defer import Deferred @@ -533,7 +538,7 @@ class TestTrialUnittest: # will crash both at test time and at teardown """ ) - result = testdir.runpytest("-vv", "-oconsole_output_style=classic") + result = pytester.runpytest("-vv", "-oconsole_output_style=classic") result.stdout.fnmatch_lines( [ "test_trial_error.py::TC::test_four FAILED", @@ -557,8 +562,8 @@ class TestTrialUnittest: ] ) - def test_trial_pdb(self, testdir): - p = testdir.makepyfile( + def test_trial_pdb(self, pytester: Pytester) -> None: + p = pytester.makepyfile( """ from twisted.trial import unittest import pytest @@ -567,12 +572,12 @@ class TestTrialUnittest: assert 0, "hellopdb" """ ) - child = testdir.spawn_pytest(p) + child = pytester.spawn_pytest(str(p)) child.expect("hellopdb") child.sendeof() - def test_trial_testcase_skip_property(self, testdir): - testpath = testdir.makepyfile( + def test_trial_testcase_skip_property(self, pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ from twisted.trial import unittest class MyTestCase(unittest.TestCase): @@ -581,11 +586,11 @@ class TestTrialUnittest: pass """ ) - reprec = testdir.inline_run(testpath, "-s") + reprec = pytester.inline_run(testpath, "-s") reprec.assertoutcome(skipped=1) - def test_trial_testfunction_skip_property(self, testdir): - testpath = testdir.makepyfile( + def test_trial_testfunction_skip_property(self, pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ from twisted.trial import unittest class MyTestCase(unittest.TestCase): @@ -594,11 +599,11 @@ class TestTrialUnittest: test_func.skip = 'dont run' """ ) - reprec = testdir.inline_run(testpath, "-s") + reprec = pytester.inline_run(testpath, "-s") reprec.assertoutcome(skipped=1) - def test_trial_testcase_todo_property(self, testdir): - testpath = testdir.makepyfile( + def test_trial_testcase_todo_property(self, pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ from twisted.trial import unittest class MyTestCase(unittest.TestCase): @@ -607,11 +612,11 @@ class TestTrialUnittest: assert 0 """ ) - reprec = testdir.inline_run(testpath, "-s") + reprec = pytester.inline_run(testpath, "-s") reprec.assertoutcome(skipped=1) - def test_trial_testfunction_todo_property(self, testdir): - testpath = testdir.makepyfile( + def test_trial_testfunction_todo_property(self, pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ from twisted.trial import unittest class MyTestCase(unittest.TestCase): @@ -620,15 +625,15 @@ class TestTrialUnittest: test_func.todo = 'dont run' """ ) - reprec = testdir.inline_run( + reprec = pytester.inline_run( testpath, "-s", *self.ignore_unclosed_socket_warning ) reprec.assertoutcome(skipped=1) -def test_djangolike_testcase(testdir): +def test_djangolike_testcase(pytester: Pytester) -> None: # contributed from Morten Breekevold - testdir.makepyfile( + pytester.makepyfile( """ from unittest import TestCase, main @@ -671,7 +676,7 @@ def test_djangolike_testcase(testdir): print("_post_teardown()") """ ) - result = testdir.runpytest("-s") + result = pytester.runpytest("-s") assert result.ret == 0 result.stdout.fnmatch_lines( [ @@ -684,8 +689,8 @@ def test_djangolike_testcase(testdir): ) -def test_unittest_not_shown_in_traceback(testdir): - testdir.makepyfile( +def test_unittest_not_shown_in_traceback(pytester: Pytester) -> None: + pytester.makepyfile( """ import unittest class t(unittest.TestCase): @@ -694,12 +699,12 @@ def test_unittest_not_shown_in_traceback(testdir): self.assertEqual(x, 4) """ ) - res = testdir.runpytest() + res = pytester.runpytest() res.stdout.no_fnmatch_line("*failUnlessEqual*") -def test_unorderable_types(testdir): - testdir.makepyfile( +def test_unorderable_types(pytester: Pytester) -> None: + pytester.makepyfile( """ import unittest class TestJoinEmpty(unittest.TestCase): @@ -713,13 +718,13 @@ def test_unorderable_types(testdir): TestFoo = make_test() """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.no_fnmatch_line("*TypeError*") assert result.ret == ExitCode.NO_TESTS_COLLECTED -def test_unittest_typerror_traceback(testdir): - testdir.makepyfile( +def test_unittest_typerror_traceback(pytester: Pytester) -> None: + pytester.makepyfile( """ import unittest class TestJoinEmpty(unittest.TestCase): @@ -727,14 +732,16 @@ def test_unittest_typerror_traceback(testdir): pass """ ) - result = testdir.runpytest() + result = pytester.runpytest() assert "TypeError" in result.stdout.str() assert result.ret == 1 @pytest.mark.parametrize("runner", ["pytest", "unittest"]) -def test_unittest_expected_failure_for_failing_test_is_xfail(testdir, runner): - script = testdir.makepyfile( +def test_unittest_expected_failure_for_failing_test_is_xfail( + pytester: Pytester, runner +) -> None: + script = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -746,19 +753,21 @@ def test_unittest_expected_failure_for_failing_test_is_xfail(testdir, runner): """ ) if runner == "pytest": - result = testdir.runpytest("-rxX") + result = pytester.runpytest("-rxX") result.stdout.fnmatch_lines( ["*XFAIL*MyTestCase*test_failing_test_is_xfail*", "*1 xfailed*"] ) else: - result = testdir.runpython(script) + result = pytester.runpython(script) result.stderr.fnmatch_lines(["*1 test in*", "*OK*(expected failures=1)*"]) assert result.ret == 0 @pytest.mark.parametrize("runner", ["pytest", "unittest"]) -def test_unittest_expected_failure_for_passing_test_is_fail(testdir, runner): - script = testdir.makepyfile( +def test_unittest_expected_failure_for_passing_test_is_fail( + pytester: Pytester, runner +) -> None: + script = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -771,20 +780,20 @@ def test_unittest_expected_failure_for_passing_test_is_fail(testdir, runner): ) if runner == "pytest": - result = testdir.runpytest("-rxX") + result = pytester.runpytest("-rxX") result.stdout.fnmatch_lines( ["*MyTestCase*test_passing_test_is_fail*", "*1 failed*"] ) else: - result = testdir.runpython(script) + result = pytester.runpython(script) result.stderr.fnmatch_lines(["*1 test in*", "*(unexpected successes=1)*"]) assert result.ret == 1 @pytest.mark.parametrize("stmt", ["return", "yield"]) -def test_unittest_setup_interaction(testdir: Testdir, stmt: str) -> None: - testdir.makepyfile( +def test_unittest_setup_interaction(pytester: Pytester, stmt: str) -> None: + pytester.makepyfile( """ import unittest import pytest @@ -811,12 +820,12 @@ def test_unittest_setup_interaction(testdir: Testdir, stmt: str) -> None: stmt=stmt ) ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(["*3 passed*"]) -def test_non_unittest_no_setupclass_support(testdir): - testpath = testdir.makepyfile( +def test_non_unittest_no_setupclass_support(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ class TestFoo(object): x = 0 @@ -837,12 +846,12 @@ def test_non_unittest_no_setupclass_support(testdir): """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) reprec.assertoutcome(passed=2) -def test_no_teardown_if_setupclass_failed(testdir): - testpath = testdir.makepyfile( +def test_no_teardown_if_setupclass_failed(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest @@ -865,13 +874,13 @@ def test_no_teardown_if_setupclass_failed(testdir): assert MyTestCase.x == 1 """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) reprec.assertoutcome(passed=1, failed=1) -def test_cleanup_functions(testdir): +def test_cleanup_functions(pytester: Pytester) -> None: """Ensure functions added with addCleanup are always called after each test ends (#6947)""" - testdir.makepyfile( + pytester.makepyfile( """ import unittest @@ -890,7 +899,7 @@ def test_cleanup_functions(testdir): assert cleanups == ["test_func_1", "test_func_2"] """ ) - result = testdir.runpytest("-v") + result = pytester.runpytest("-v") result.stdout.fnmatch_lines( [ "*::test_func_1 PASSED *", @@ -900,8 +909,8 @@ def test_cleanup_functions(testdir): ) -def test_issue333_result_clearing(testdir): - testdir.makeconftest( +def test_issue333_result_clearing(pytester: Pytester) -> None: + pytester.makeconftest( """ import pytest @pytest.hookimpl(hookwrapper=True) @@ -910,7 +919,7 @@ def test_issue333_result_clearing(testdir): assert 0 """ ) - testdir.makepyfile( + pytester.makepyfile( """ import unittest class TestIt(unittest.TestCase): @@ -919,12 +928,12 @@ def test_issue333_result_clearing(testdir): """ ) - reprec = testdir.inline_run() + reprec = pytester.inline_run() reprec.assertoutcome(failed=1) -def test_unittest_raise_skip_issue748(testdir): - testdir.makepyfile( +def test_unittest_raise_skip_issue748(pytester: Pytester) -> None: + pytester.makepyfile( test_foo=""" import unittest @@ -933,7 +942,7 @@ def test_unittest_raise_skip_issue748(testdir): raise unittest.SkipTest('skipping due to reasons') """ ) - result = testdir.runpytest("-v", "-rs") + result = pytester.runpytest("-v", "-rs") result.stdout.fnmatch_lines( """ *SKIP*[1]*test_foo.py*skipping due to reasons* @@ -942,8 +951,8 @@ def test_unittest_raise_skip_issue748(testdir): ) -def test_unittest_skip_issue1169(testdir): - testdir.makepyfile( +def test_unittest_skip_issue1169(pytester: Pytester) -> None: + pytester.makepyfile( test_foo=""" import unittest @@ -953,7 +962,7 @@ def test_unittest_skip_issue1169(testdir): self.fail() """ ) - result = testdir.runpytest("-v", "-rs") + result = pytester.runpytest("-v", "-rs") result.stdout.fnmatch_lines( """ *SKIP*[1]*skipping due to reasons* @@ -962,8 +971,8 @@ def test_unittest_skip_issue1169(testdir): ) -def test_class_method_containing_test_issue1558(testdir): - testdir.makepyfile( +def test_class_method_containing_test_issue1558(pytester: Pytester) -> None: + pytester.makepyfile( test_foo=""" import unittest @@ -975,16 +984,16 @@ def test_class_method_containing_test_issue1558(testdir): test_should_not_run.__test__ = False """ ) - reprec = testdir.inline_run() + reprec = pytester.inline_run() reprec.assertoutcome(passed=1) @pytest.mark.parametrize("base", ["builtins.object", "unittest.TestCase"]) -def test_usefixtures_marker_on_unittest(base, testdir): +def test_usefixtures_marker_on_unittest(base, pytester: Pytester) -> None: """#3498""" module = base.rsplit(".", 1)[0] pytest.importorskip(module) - testdir.makepyfile( + pytester.makepyfile( conftest=""" import pytest @@ -1013,7 +1022,7 @@ def test_usefixtures_marker_on_unittest(base, testdir): """ ) - testdir.makepyfile( + pytester.makepyfile( """ import pytest import {module} @@ -1038,16 +1047,16 @@ def test_usefixtures_marker_on_unittest(base, testdir): ) ) - result = testdir.runpytest("-s") + result = pytester.runpytest("-s") result.assert_outcomes(passed=2) -def test_testcase_handles_init_exceptions(testdir): +def test_testcase_handles_init_exceptions(pytester: Pytester) -> None: """ Regression test to make sure exceptions in the __init__ method are bubbled up correctly. See https://github.com/pytest-dev/pytest/issues/3788 """ - testdir.makepyfile( + pytester.makepyfile( """ from unittest import TestCase import pytest @@ -1058,14 +1067,14 @@ def test_testcase_handles_init_exceptions(testdir): pass """ ) - result = testdir.runpytest() + result = pytester.runpytest() assert "should raise this exception" in result.stdout.str() result.stdout.no_fnmatch_line("*ERROR at teardown of MyTestCase.test_hello*") -def test_error_message_with_parametrized_fixtures(testdir): - testdir.copy_example("unittest/test_parametrized_fixture_error_message.py") - result = testdir.runpytest() +def test_error_message_with_parametrized_fixtures(pytester: Pytester) -> None: + pytester.copy_example("unittest/test_parametrized_fixture_error_message.py") + result = pytester.runpytest() result.stdout.fnmatch_lines( [ "*test_two does not support fixtures*", @@ -1083,15 +1092,17 @@ def test_error_message_with_parametrized_fixtures(testdir): ("test_setup_skip_module.py", "1 error"), ], ) -def test_setup_inheritance_skipping(testdir, test_name, expected_outcome): +def test_setup_inheritance_skipping( + pytester: Pytester, test_name, expected_outcome +) -> None: """Issue #4700""" - testdir.copy_example(f"unittest/{test_name}") - result = testdir.runpytest() + pytester.copy_example(f"unittest/{test_name}") + result = pytester.runpytest() result.stdout.fnmatch_lines([f"* {expected_outcome} in *"]) -def test_BdbQuit(testdir): - testdir.makepyfile( +def test_BdbQuit(pytester: Pytester) -> None: + pytester.makepyfile( test_foo=""" import unittest @@ -1104,12 +1115,12 @@ def test_BdbQuit(testdir): pass """ ) - reprec = testdir.inline_run() + reprec = pytester.inline_run() reprec.assertoutcome(failed=1, passed=1) -def test_exit_outcome(testdir): - testdir.makepyfile( +def test_exit_outcome(pytester: Pytester) -> None: + pytester.makepyfile( test_foo=""" import pytest import unittest @@ -1122,11 +1133,11 @@ def test_exit_outcome(testdir): pass """ ) - result = testdir.runpytest() + result = pytester.runpytest() result.stdout.fnmatch_lines(["*Exit: pytest_exit called*", "*= no tests ran in *"]) -def test_trace(testdir, monkeypatch): +def test_trace(pytester: Pytester, monkeypatch: MonkeyPatch) -> None: calls = [] def check_call(*args, **kwargs): @@ -1141,7 +1152,7 @@ def test_trace(testdir, monkeypatch): monkeypatch.setattr("_pytest.debugging.pytestPDB._init_pdb", check_call) - p1 = testdir.makepyfile( + p1 = pytester.makepyfile( """ import unittest @@ -1150,12 +1161,12 @@ def test_trace(testdir, monkeypatch): self.assertEqual('foo', 'foo') """ ) - result = testdir.runpytest("--trace", str(p1)) + result = pytester.runpytest("--trace", str(p1)) assert len(calls) == 2 assert result.ret == 0 -def test_pdb_teardown_called(testdir, monkeypatch) -> None: +def test_pdb_teardown_called(pytester: Pytester, monkeypatch: MonkeyPatch) -> None: """Ensure tearDown() is always called when --pdb is given in the command-line. We delay the normal tearDown() calls when --pdb is given, so this ensures we are calling @@ -1166,7 +1177,7 @@ def test_pdb_teardown_called(testdir, monkeypatch) -> None: pytest, "test_pdb_teardown_called_teardowns", teardowns, raising=False ) - testdir.makepyfile( + pytester.makepyfile( """ import unittest import pytest @@ -1182,7 +1193,7 @@ def test_pdb_teardown_called(testdir, monkeypatch) -> None: pass """ ) - result = testdir.runpytest_inprocess("--pdb") + result = pytester.runpytest_inprocess("--pdb") result.stdout.fnmatch_lines("* 2 passed in *") assert teardowns == [ "test_pdb_teardown_called.MyTestCase.test_1", @@ -1191,12 +1202,14 @@ def test_pdb_teardown_called(testdir, monkeypatch) -> None: @pytest.mark.parametrize("mark", ["@unittest.skip", "@pytest.mark.skip"]) -def test_pdb_teardown_skipped(testdir, monkeypatch, mark: str) -> None: +def test_pdb_teardown_skipped( + pytester: Pytester, monkeypatch: MonkeyPatch, mark: str +) -> None: """With --pdb, setUp and tearDown should not be called for skipped tests.""" tracked: List[str] = [] monkeypatch.setattr(pytest, "test_pdb_teardown_skipped", tracked, raising=False) - testdir.makepyfile( + pytester.makepyfile( """ import unittest import pytest @@ -1217,29 +1230,29 @@ def test_pdb_teardown_skipped(testdir, monkeypatch, mark: str) -> None: mark=mark ) ) - result = testdir.runpytest_inprocess("--pdb") + result = pytester.runpytest_inprocess("--pdb") result.stdout.fnmatch_lines("* 1 skipped in *") assert tracked == [] -def test_async_support(testdir): +def test_async_support(pytester: Pytester) -> None: pytest.importorskip("unittest.async_case") - testdir.copy_example("unittest/test_unittest_asyncio.py") - reprec = testdir.inline_run() + pytester.copy_example("unittest/test_unittest_asyncio.py") + reprec = pytester.inline_run() reprec.assertoutcome(failed=1, passed=2) -def test_asynctest_support(testdir): +def test_asynctest_support(pytester: Pytester) -> None: """Check asynctest support (#7110)""" pytest.importorskip("asynctest") - testdir.copy_example("unittest/test_unittest_asynctest.py") - reprec = testdir.inline_run() + pytester.copy_example("unittest/test_unittest_asynctest.py") + reprec = pytester.inline_run() reprec.assertoutcome(failed=1, passed=2) -def test_plain_unittest_does_not_support_async(testdir): +def test_plain_unittest_does_not_support_async(pytester: Pytester) -> None: """Async functions in plain unittest.TestCase subclasses are not supported without plugins. This test exists here to avoid introducing this support by accident, leading users @@ -1247,8 +1260,8 @@ def test_plain_unittest_does_not_support_async(testdir): See https://github.com/pytest-dev/pytest-asyncio/issues/180 for more context. """ - testdir.copy_example("unittest/test_unittest_plain_async.py") - result = testdir.runpytest_subprocess() + pytester.copy_example("unittest/test_unittest_plain_async.py") + result = pytester.runpytest_subprocess() if hasattr(sys, "pypy_version_info"): # in PyPy we can't reliable get the warning about the coroutine not being awaited, # because it depends on the coroutine being garbage collected; given that @@ -1265,8 +1278,8 @@ def test_plain_unittest_does_not_support_async(testdir): @pytest.mark.skipif( sys.version_info < (3, 8), reason="Feature introduced in Python 3.8" ) -def test_do_class_cleanups_on_success(testdir): - testpath = testdir.makepyfile( +def test_do_class_cleanups_on_success(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -1284,7 +1297,7 @@ def test_do_class_cleanups_on_success(testdir): assert MyTestCase.values == [1] """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() assert failed == 0 assert passed == 3 @@ -1293,8 +1306,8 @@ def test_do_class_cleanups_on_success(testdir): @pytest.mark.skipif( sys.version_info < (3, 8), reason="Feature introduced in Python 3.8" ) -def test_do_class_cleanups_on_setupclass_failure(testdir): - testpath = testdir.makepyfile( +def test_do_class_cleanups_on_setupclass_failure(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -1311,7 +1324,7 @@ def test_do_class_cleanups_on_setupclass_failure(testdir): assert MyTestCase.values == [1] """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() assert failed == 1 assert passed == 1 @@ -1320,8 +1333,8 @@ def test_do_class_cleanups_on_setupclass_failure(testdir): @pytest.mark.skipif( sys.version_info < (3, 8), reason="Feature introduced in Python 3.8" ) -def test_do_class_cleanups_on_teardownclass_failure(testdir): - testpath = testdir.makepyfile( +def test_do_class_cleanups_on_teardownclass_failure(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -1342,13 +1355,13 @@ def test_do_class_cleanups_on_teardownclass_failure(testdir): assert MyTestCase.values == [1] """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() assert passed == 3 -def test_do_cleanups_on_success(testdir): - testpath = testdir.makepyfile( +def test_do_cleanups_on_success(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -1365,14 +1378,14 @@ def test_do_cleanups_on_success(testdir): assert MyTestCase.values == [1, 1] """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() assert failed == 0 assert passed == 3 -def test_do_cleanups_on_setup_failure(testdir): - testpath = testdir.makepyfile( +def test_do_cleanups_on_setup_failure(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -1390,14 +1403,14 @@ def test_do_cleanups_on_setup_failure(testdir): assert MyTestCase.values == [1, 1] """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() assert failed == 2 assert passed == 1 -def test_do_cleanups_on_teardown_failure(testdir): - testpath = testdir.makepyfile( +def test_do_cleanups_on_teardown_failure(pytester: Pytester) -> None: + testpath = pytester.makepyfile( """ import unittest class MyTestCase(unittest.TestCase): @@ -1416,7 +1429,7 @@ def test_do_cleanups_on_teardown_failure(testdir): assert MyTestCase.values == [1, 1] """ ) - reprec = testdir.inline_run(testpath) + reprec = pytester.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() assert failed == 2 assert passed == 1