Merge pull request #8168 from antonblr/testdir-to-pytester-incr2

tests: Migrate to pytester - final update
This commit is contained in:
Ran Benita 2020-12-19 13:32:20 +02:00 committed by GitHub
commit 89dcfbf293
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 697 additions and 576 deletions

View File

@ -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: Union[str, "os.PathLike[str]"]) -> bool:
warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
return self.session.isinitpath(path)

View File

@ -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: Union[str, "os.PathLike[str]"]) -> bool:
warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
return self.session.isinitpath(path)

View File

@ -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

View File

@ -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": """

View File

@ -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

View File

@ -24,8 +24,8 @@ _ENVIRON_PYTHONBREAKPOINT = os.environ.get("PYTHONBREAKPOINT", "")
def pdb_env(request):
if "pytester" in request.fixturenames:
# Disable pdb++ with inner tests.
pytester = request.getfixturevalue("testdir")
pytester.monkeypatch.setenv("PDBPP_HIJACK_PDB", "0")
pytester = request.getfixturevalue("pytester")
pytester._monkeypatch.setenv("PDBPP_HIJACK_PDB", "0")
def runpdb_and_get_report(pytester: Pytester, source: str):

View File

@ -4,51 +4,62 @@ 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 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
@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:
return xmlschema.XMLSchema(f)
class RunAndParse:
def __init__(self, pytester: Pytester, schema: xmlschema.XMLSchema) -> None:
self.pytester = pytester
self.schema = schema
def __call__(
self, *args: Union[str, "os.PathLike[str]"], family: Optional[str] = "xunit1"
) -> Tuple[RunResult, "DomNode"]:
if family:
args = ("-o", "junit_family=" + family) + args
xml_path = self.pytester.path.joinpath("junit.xml")
result = self.pytester.runpytest("--junitxml=%s" % xml_path, *args)
if family == "xunit2":
with xml_path.open() as f:
self.schema.validate(f)
xmldoc = minidom.parse(str(xml_path))
return result, DomNode(xmldoc)
@pytest.fixture
def run_and_parse(testdir, schema):
def run_and_parse(pytester: Pytester, schema: xmlschema.XMLSchema) -> RunAndParse:
"""Fixture that returns a function that can be used to execute pytest and
return the parsed ``DomNode`` of the root xml node.
The ``family`` parameter is used to configure the ``junit_family`` of the written report.
"xunit2" is also automatically validated against the schema.
"""
def run(*args, family="xunit1"):
if family:
args = ("-o", "junit_family=" + family) + args
xml_path = testdir.tmpdir.join("junit.xml")
result = testdir.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 RunAndParse(pytester, schema)
def assert_attr(node, **kwargs):
@ -130,8 +141,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
def test_pass():
@ -154,8 +167,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.fixture
@ -181,8 +196,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
def test_pass():
pass
@ -193,8 +210,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
def test_pass():
pass
@ -206,8 +225,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: RunAndParse, mock_timing
) -> None:
pytester.makepyfile(
"""
from _pytest import timing
def setup_module():
@ -226,8 +247,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: str,
run_and_parse: RunAndParse,
) -> 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 +264,7 @@ class TestPython:
monkeypatch.setattr(LogXML, "node_reporter", node_reporter_wrapper)
testdir.makepyfile(
pytester.makepyfile(
"""
def test_foo():
pass
@ -256,8 +281,10 @@ 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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@ -279,8 +306,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@ -302,8 +331,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@ -331,8 +362,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
def test_skip():
@ -349,8 +382,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.skip(reason="hello24")
@ -371,9 +406,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
GLOBAL_CONDITION = True
@ -395,9 +430,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.skip(reason="foo")
@ -411,8 +446,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
class TestClass(object):
def test_method(self):
@ -429,9 +466,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: RunAndParse, xunit_family: str
) -> 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 +479,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: RunAndParse, xunit_family: str
) -> 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 +499,13 @@ 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: RunAndParse,
xunit_family,
) -> None:
pytester.makepyfile(
"""
import logging
import sys
@ -521,8 +566,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import sys
def test_fail():
@ -536,8 +583,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.parametrize('arg1', "<&'", ids="<&'")
@ -564,8 +613,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
def test_func():
assert 0
@ -586,8 +637,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
def test_xfail():
@ -604,8 +657,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.xfail(reason="42")
@ -625,8 +680,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: str, run_and_parse: RunAndParse
) -> None:
pytester.makepyfile(
"""
import sys
import pytest
@ -652,8 +709,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.xfail
@ -669,8 +728,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.xfail(strict=True, reason="This needs to fail!")
@ -688,8 +749,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: RunAndParse, xunit_family: str
) -> 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 +762,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: RunAndParse) -> None:
value = "hx\xc4\x85\xc4\x87\n"
testdir.makepyfile(
pytester.makepyfile(
"""\
# coding: latin1
def test_hello():
@ -716,9 +779,11 @@ 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: RunAndParse
) -> None:
"""This test did fail when the escaping wasn't strict."""
testdir.makepyfile(
pytester.makepyfile(
"""
M1 = '\x01\x02\x03\x04'
@ -732,8 +797,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: RunAndParse, junit_logging: str
) -> None:
pytester.makepyfile(
"""
def test_pass():
print('hello-stdout')
@ -753,8 +820,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: RunAndParse, junit_logging: str
) -> None:
pytester.makepyfile(
"""
import sys
def test_pass():
@ -775,8 +844,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: RunAndParse, junit_logging: str
) -> None:
pytester.makepyfile(
"""
import pytest
@ -802,8 +873,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: RunAndParse, junit_logging: str
) -> None:
pytester.makepyfile(
"""
import sys
import pytest
@ -830,8 +903,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: RunAndParse, junit_logging: str
) -> None:
pytester.makepyfile(
"""
import sys
import pytest
@ -858,7 +933,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 +941,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 +957,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 +973,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: RunAndParse, xunit_family: str
) -> None:
pytester.makeconftest(
"""
import pytest
def pytest_collect_file(path, parent):
@ -912,7 +989,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 +1002,9 @@ class TestNonPython:
@pytest.mark.parametrize("junit_logging", ["no", "system-out"])
def test_nullbyte(testdir, junit_logging):
def test_nullbyte(pytester: Pytester, junit_logging: str) -> 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 +1013,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 +1024,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: str) -> None:
# Check if the null byte gets replaced
testdir.makepyfile(
pytester.makepyfile(
"""
import sys
def test_print_nullbyte():
@ -958,16 +1035,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 +1080,54 @@ 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: RunAndParse
) -> None:
pytester.makepyfile(
"""\
import pytest
@pytest.mark.parametrize('char', ["\\x00"])
@ -1062,8 +1141,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: RunAndParse
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.parametrize('param', ["double::colon"])
@ -1078,8 +1159,10 @@ 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: RunAndParse
) -> None:
pytester.makepyfile(
"""
import pytest
class TestClass(object):
@ -1095,8 +1178,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 +1208,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: RunAndParse) -> None:
pytester.makepyfile(
"""
import pytest
@ -1147,8 +1230,10 @@ 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: RunAndParse
) -> None:
pytester.makepyfile(
"""
def test_record_with_same_name(record_property):
record_property("foo", "bar")
@ -1165,8 +1250,10 @@ 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: str
) -> None:
pytester.makepyfile(
"""
def test_record({fixture_name}):
{fixture_name}("foo", "bar")
@ -1174,19 +1261,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: RunAndParse) -> None:
pytester.makeini(
"""
[pytest]
junit_family = xunit1
"""
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
@ -1209,15 +1296,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: str, run_and_parse: RunAndParse
) -> 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 +1335,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: RunAndParse
) -> 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 +1362,10 @@ 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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
def test_x():
pass
@ -1285,8 +1378,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: RunAndParse) -> None:
f = pytester.makepyfile(
"""
def test_pass():
pass
@ -1299,10 +1392,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: RunAndParse
) -> 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 +1410,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: RunAndParse) -> None:
# issue 1259
testdir.makeconftest(
pytester.makeconftest(
"""
import pytest
class FunItem(pytest.Item):
@ -1341,7 +1436,7 @@ def test_fancy_items_regression(testdir, run_and_parse):
"""
)
testdir.makepyfile(
pytester.makepyfile(
"""
def test_pass():
pass
@ -1368,8 +1463,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: str) -> None:
path = pytester.path.joinpath("test_global_properties.xml")
log = LogXML(str(path), None, family=xunit_family)
class Report(BaseReport):
@ -1402,9 +1497,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 +1524,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: RunAndParse, xunit_family: str
) -> None:
pytester.makepyfile(
"""
def test_func1(record_testsuite_property):
record_testsuite_property("stats", "all good")
@ -1449,27 +1546,29 @@ 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: bool
) -> 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 +1577,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: str, run_and_parse: RunAndParse, xunit_family: str
) -> None:
if suite_name:
testdir.makeini(
pytester.makeini(
"""
[pytest]
junit_suite_name={suite_name}
@ -1492,7 +1593,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 +1607,10 @@ 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: RunAndParse
) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.skip(reason='1 <> 2')
@ -1524,9 +1627,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: RunAndParse, xunit_family: str
) -> None:
pytester.makeini(
"""
[pytest]
junit_log_passing_tests=False
@ -1536,7 +1639,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 +1661,12 @@ 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: str,
run_and_parse: RunAndParse,
xunit_family: str,
) -> None:
pytester.makeini(
"""
[pytest]
junit_log_passing_tests=False
@ -1569,7 +1675,7 @@ def test_logging_passing_tests_disabled_logs_output_for_failing_test_issue5430(
family=xunit_family
)
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging

View File

@ -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

View File

@ -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 *",

View File

@ -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")

View File

@ -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) -> None:
"""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,51 +264,52 @@ 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:
@ -318,14 +319,14 @@ class TestSysModulesSnapshot:
original = dict(sys.modules)
assert self.key not in sys.modules
snapshot = SysModulesSnapshot()
sys.modules[self.key] = "something" # type: ignore
sys.modules[self.key] = ModuleType("something")
assert self.key in sys.modules
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, ModuleType("something"))
assert self.key in sys.modules
original = dict(sys.modules)
snapshot = SysModulesSnapshot()
@ -334,38 +335,39 @@ 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, ModuleType("something"))
assert self.key in sys.modules
original = dict(sys.modules)
snapshot = SysModulesSnapshot()
sys.modules[self.key] = "something else" # type: ignore
sys.modules[self.key] = ModuleType("something else")
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):
return name in (key[0], key[1], "some-other-key")
snapshot = SysModulesSnapshot(preserve=preserve)
sys.modules[key[0]] = original[key[0]] = "something else0" # type: ignore
sys.modules[key[1]] = original[key[1]] = "something else1" # type: ignore
sys.modules[key[2]] = "something else2" # type: ignore
sys.modules[key[0]] = original[key[0]] = ModuleType("something else0")
sys.modules[key[1]] = original[key[1]] = ModuleType("something else1")
sys.modules[key[2]] = ModuleType("something else2")
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)
replacement[self.key] = "life of brian" # type: ignore
replacement[self.key] = ModuleType("life of brian")
snapshot = SysModulesSnapshot()
monkeypatch.setattr(sys, "modules", replacement)
snapshot.restore()
@ -381,7 +383,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 +406,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 +421,49 @@ 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(
result = pytester.runpytest_inprocess(
"-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 +471,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 +535,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 +556,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 +617,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 +628,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 +638,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 +647,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 +658,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 +672,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 +685,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 +704,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 +742,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) == "<RunResult ret=ExitCode.TESTS_FAILED len(stdout.lines)=3"
" len(stderr.lines)=4 duration=0.50s>"
)
# 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) == "<RunResult ret=99 len(stdout.lines)=3"
" len(stderr.lines)=4 duration=0.50s>"
)
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,13 +772,13 @@ 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}
def test_parse_summary_line_always_plural():
def test_parse_summary_line_always_plural() -> None:
"""Parsing summaries always returns plural nouns (#6505)"""
lines = [
"some output 1",
@ -784,7 +786,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 +799,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,12 +807,12 @@ 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):
def test_testtmproot(testdir) -> None:
"""Check test_tmproot is a py.path attribute for backward compatibility."""
assert testdir.test_tmproot.check(dir=1)

File diff suppressed because it is too large Load Diff