tests: Migrate to pytester - incremental update (#8145)

This commit is contained in:
Anton 2020-12-15 03:02:32 -08:00 committed by GitHub
parent cb8142b8ec
commit 8eef8c6004
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 801 additions and 703 deletions

View File

@ -5,6 +5,7 @@ import os
import queue
import sys
import textwrap
from pathlib import Path
from typing import Any
from typing import Dict
from typing import Tuple
@ -19,7 +20,10 @@ from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo
from _pytest._code.code import FormattedExcinfo
from _pytest._io import TerminalWriter
from _pytest.pathlib import import_path
from _pytest.pytester import LineMatcher
from _pytest.pytester import Pytester
if TYPE_CHECKING:
from _pytest._code.code import _TracebackStyle
@ -155,10 +159,10 @@ class TestTraceback_f_g_h:
newtraceback = traceback.cut(path=path, lineno=firstlineno + 2)
assert len(newtraceback) == 1
def test_traceback_cut_excludepath(self, testdir):
p = testdir.makepyfile("def f(): raise ValueError")
def test_traceback_cut_excludepath(self, pytester: Pytester) -> None:
p = pytester.makepyfile("def f(): raise ValueError")
with pytest.raises(ValueError) as excinfo:
p.pyimport().f()
import_path(p).f() # type: ignore[attr-defined]
basedir = py.path.local(pytest.__file__).dirpath()
newtraceback = excinfo.traceback.cut(excludepath=basedir)
for x in newtraceback:
@ -406,8 +410,8 @@ def test_match_succeeds():
excinfo.match(r".*zero.*")
def test_match_raises_error(testdir):
testdir.makepyfile(
def test_match_raises_error(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
def test_division_zero():
@ -416,14 +420,14 @@ def test_match_raises_error(testdir):
excinfo.match(r'[123]+')
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
assert result.ret != 0
exc_msg = "Regex pattern '[[]123[]]+' does not match 'division by zero'."
result.stdout.fnmatch_lines([f"E * AssertionError: {exc_msg}"])
result.stdout.no_fnmatch_line("*__tracebackhide__ = True*")
result = testdir.runpytest("--fulltrace")
result = pytester.runpytest("--fulltrace")
assert result.ret != 0
result.stdout.fnmatch_lines(
["*__tracebackhide__ = True*", f"E * AssertionError: {exc_msg}"]
@ -432,15 +436,14 @@ def test_match_raises_error(testdir):
class TestFormattedExcinfo:
@pytest.fixture
def importasmod(self, request, _sys_snapshot):
def importasmod(self, tmp_path: Path, _sys_snapshot):
def importasmod(source):
source = textwrap.dedent(source)
tmpdir = request.getfixturevalue("tmpdir")
modpath = tmpdir.join("mod.py")
tmpdir.ensure("__init__.py")
modpath.write(source)
modpath = tmp_path.joinpath("mod.py")
tmp_path.joinpath("__init__.py").touch()
modpath.write_text(source)
importlib.invalidate_caches()
return modpath.pyimport()
return import_path(modpath)
return importasmod
@ -682,7 +685,7 @@ raise ValueError()
p = FormattedExcinfo(style="short")
reprtb = p.repr_traceback_entry(excinfo.traceback[-2])
lines = reprtb.lines
basename = py.path.local(mod.__file__).basename
basename = Path(mod.__file__).name
assert lines[0] == " func1()"
assert reprtb.reprfileloc is not None
assert basename in str(reprtb.reprfileloc.path)
@ -948,7 +951,9 @@ raise ValueError()
assert line.endswith("mod.py")
assert tw_mock.lines[12] == ":3: ValueError"
def test_toterminal_long_missing_source(self, importasmod, tmpdir, tw_mock):
def test_toterminal_long_missing_source(
self, importasmod, tmp_path: Path, tw_mock
) -> None:
mod = importasmod(
"""
def g(x):
@ -958,7 +963,7 @@ raise ValueError()
"""
)
excinfo = pytest.raises(ValueError, mod.f)
tmpdir.join("mod.py").remove()
tmp_path.joinpath("mod.py").unlink()
excinfo.traceback = excinfo.traceback.filter()
repr = excinfo.getrepr()
repr.toterminal(tw_mock)
@ -978,7 +983,9 @@ raise ValueError()
assert line.endswith("mod.py")
assert tw_mock.lines[10] == ":3: ValueError"
def test_toterminal_long_incomplete_source(self, importasmod, tmpdir, tw_mock):
def test_toterminal_long_incomplete_source(
self, importasmod, tmp_path: Path, tw_mock
) -> None:
mod = importasmod(
"""
def g(x):
@ -988,7 +995,7 @@ raise ValueError()
"""
)
excinfo = pytest.raises(ValueError, mod.f)
tmpdir.join("mod.py").write("asdf")
tmp_path.joinpath("mod.py").write_text("asdf")
excinfo.traceback = excinfo.traceback.filter()
repr = excinfo.getrepr()
repr.toterminal(tw_mock)
@ -1374,16 +1381,18 @@ def test_repr_traceback_with_unicode(style, encoding):
assert repr_traceback is not None
def test_cwd_deleted(testdir):
testdir.makepyfile(
def test_cwd_deleted(pytester: Pytester) -> None:
pytester.makepyfile(
"""
def test(tmpdir):
tmpdir.chdir()
tmpdir.remove()
import os
def test(tmp_path):
os.chdir(tmp_path)
tmp_path.unlink()
assert False
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["* 1 failed in *"])
result.stdout.no_fnmatch_line("*INTERNALERROR*")
result.stderr.no_fnmatch_line("*INTERNALERROR*")

View File

@ -1,3 +1,6 @@
def test_510(testdir):
testdir.copy_example("issue_519.py")
testdir.runpytest("issue_519.py")
from _pytest.pytester import Pytester
def test_510(pytester: Pytester) -> None:
pytester.copy_example("issue_519.py")
pytester.runpytest("issue_519.py")

View File

@ -3,6 +3,7 @@ import os
import re
import shutil
import sys
from pathlib import Path
from typing import Generator
from unittest import mock
@ -64,10 +65,10 @@ win32 = int(sys.platform == "win32")
class TestTerminalWriter:
@pytest.fixture(params=["path", "stringio"])
def tw(
self, request, tmpdir
self, request, tmp_path: Path
) -> Generator[terminalwriter.TerminalWriter, None, None]:
if request.param == "path":
p = tmpdir.join("tmpfile")
p = tmp_path.joinpath("tmpfile")
f = open(str(p), "w+", encoding="utf8")
tw = terminalwriter.TerminalWriter(f)

View File

@ -2,14 +2,14 @@ import logging
import pytest
from _pytest.logging import caplog_records_key
from _pytest.pytester import Testdir
from _pytest.pytester import Pytester
logger = logging.getLogger(__name__)
sublogger = logging.getLogger(__name__ + ".baz")
def test_fixture_help(testdir):
result = testdir.runpytest("--fixtures")
def test_fixture_help(pytester: Pytester) -> None:
result = pytester.runpytest("--fixtures")
result.stdout.fnmatch_lines(["*caplog*"])
@ -28,12 +28,12 @@ def test_change_level(caplog):
assert "CRITICAL" in caplog.text
def test_change_level_undo(testdir: Testdir) -> None:
def test_change_level_undo(pytester: Pytester) -> None:
"""Ensure that 'set_level' is undone after the end of the test.
Tests the logging output themselves (affacted both by logger and handler levels).
"""
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -49,17 +49,17 @@ def test_change_level_undo(testdir: Testdir) -> None:
assert 0
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*log from test1*", "*2 failed in *"])
result.stdout.no_fnmatch_line("*log from test2*")
def test_change_level_undos_handler_level(testdir: Testdir) -> None:
def test_change_level_undos_handler_level(pytester: Pytester) -> None:
"""Ensure that 'set_level' is undone after the end of the test (handler).
Issue #7569. Tests the handler level specifically.
"""
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -78,7 +78,7 @@ def test_change_level_undos_handler_level(testdir: Testdir) -> None:
assert caplog.handler.level == 43
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.assert_outcomes(passed=3)
@ -172,8 +172,8 @@ def test_caplog_captures_for_all_stages(caplog, logging_during_setup_and_teardow
assert set(caplog._item._store[caplog_records_key]) == {"setup", "call"}
def test_ini_controls_global_log_level(testdir):
testdir.makepyfile(
def test_ini_controls_global_log_level(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
import logging
@ -187,20 +187,20 @@ def test_ini_controls_global_log_level(testdir):
assert 'ERROR' in caplog.text
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_level=ERROR
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
# make sure that that we get a '0' exit code for the testsuite
assert result.ret == 0
def test_caplog_can_override_global_log_level(testdir):
testdir.makepyfile(
def test_caplog_can_override_global_log_level(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
import logging
@ -227,19 +227,19 @@ def test_caplog_can_override_global_log_level(testdir):
assert "message won't be shown" not in caplog.text
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_level=WARNING
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
assert result.ret == 0
def test_caplog_captures_despite_exception(testdir):
testdir.makepyfile(
def test_caplog_captures_despite_exception(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
import logging
@ -255,26 +255,28 @@ def test_caplog_captures_despite_exception(testdir):
raise Exception()
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_level=WARNING
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*ERROR message will be shown*"])
result.stdout.no_fnmatch_line("*DEBUG message won't be shown*")
assert result.ret == 1
def test_log_report_captures_according_to_config_option_upon_failure(testdir):
def test_log_report_captures_according_to_config_option_upon_failure(
pytester: Pytester,
) -> None:
"""Test that upon failure:
(1) `caplog` succeeded to capture the DEBUG message and assert on it => No `Exception` is raised.
(2) The `DEBUG` message does NOT appear in the `Captured log call` report.
(3) The stdout, `INFO`, and `WARNING` messages DO appear in the test reports due to `--log-level=INFO`.
"""
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -299,7 +301,7 @@ def test_log_report_captures_according_to_config_option_upon_failure(testdir):
"""
)
result = testdir.runpytest("--log-level=INFO")
result = pytester.runpytest("--log-level=INFO")
result.stdout.no_fnmatch_line("*Exception: caplog failed to capture DEBUG*")
result.stdout.no_fnmatch_line("*DEBUG log message*")
result.stdout.fnmatch_lines(

View File

@ -6,12 +6,13 @@ from typing import cast
import pytest
from _pytest.capture import CaptureManager
from _pytest.config import ExitCode
from _pytest.pytester import Testdir
from _pytest.fixtures import FixtureRequest
from _pytest.pytester import Pytester
from _pytest.terminal import TerminalReporter
def test_nothing_logged(testdir):
testdir.makepyfile(
def test_nothing_logged(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import sys
@ -21,7 +22,7 @@ def test_nothing_logged(testdir):
assert False
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
assert result.ret == 1
result.stdout.fnmatch_lines(["*- Captured stdout call -*", "text going to stdout"])
result.stdout.fnmatch_lines(["*- Captured stderr call -*", "text going to stderr"])
@ -29,8 +30,8 @@ def test_nothing_logged(testdir):
result.stdout.fnmatch_lines(["*- Captured *log call -*"])
def test_messages_logged(testdir):
testdir.makepyfile(
def test_messages_logged(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import sys
import logging
@ -44,15 +45,15 @@ def test_messages_logged(testdir):
assert False
"""
)
result = testdir.runpytest("--log-level=INFO")
result = pytester.runpytest("--log-level=INFO")
assert result.ret == 1
result.stdout.fnmatch_lines(["*- Captured *log call -*", "*text going to logger*"])
result.stdout.fnmatch_lines(["*- Captured stdout call -*", "text going to stdout"])
result.stdout.fnmatch_lines(["*- Captured stderr call -*", "text going to stderr"])
def test_root_logger_affected(testdir):
testdir.makepyfile(
def test_root_logger_affected(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import logging
logger = logging.getLogger()
@ -65,8 +66,8 @@ def test_root_logger_affected(testdir):
assert 0
"""
)
log_file = testdir.tmpdir.join("pytest.log").strpath
result = testdir.runpytest("--log-level=ERROR", "--log-file=pytest.log")
log_file = str(pytester.path.joinpath("pytest.log"))
result = pytester.runpytest("--log-level=ERROR", "--log-file=pytest.log")
assert result.ret == 1
# The capture log calls in the stdout section only contain the
@ -87,8 +88,8 @@ def test_root_logger_affected(testdir):
assert "error text going to logger" in contents
def test_log_cli_level_log_level_interaction(testdir):
testdir.makepyfile(
def test_log_cli_level_log_level_interaction(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import logging
logger = logging.getLogger()
@ -102,7 +103,7 @@ def test_log_cli_level_log_level_interaction(testdir):
"""
)
result = testdir.runpytest("--log-cli-level=INFO", "--log-level=ERROR")
result = pytester.runpytest("--log-cli-level=INFO", "--log-level=ERROR")
assert result.ret == 1
result.stdout.fnmatch_lines(
@ -117,8 +118,8 @@ def test_log_cli_level_log_level_interaction(testdir):
result.stdout.no_re_match_line("DEBUG")
def test_setup_logging(testdir):
testdir.makepyfile(
def test_setup_logging(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import logging
@ -132,7 +133,7 @@ def test_setup_logging(testdir):
assert False
"""
)
result = testdir.runpytest("--log-level=INFO")
result = pytester.runpytest("--log-level=INFO")
assert result.ret == 1
result.stdout.fnmatch_lines(
[
@ -144,8 +145,8 @@ def test_setup_logging(testdir):
)
def test_teardown_logging(testdir):
testdir.makepyfile(
def test_teardown_logging(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import logging
@ -159,7 +160,7 @@ def test_teardown_logging(testdir):
assert False
"""
)
result = testdir.runpytest("--log-level=INFO")
result = pytester.runpytest("--log-level=INFO")
assert result.ret == 1
result.stdout.fnmatch_lines(
[
@ -172,9 +173,9 @@ def test_teardown_logging(testdir):
@pytest.mark.parametrize("enabled", [True, False])
def test_log_cli_enabled_disabled(testdir, enabled):
def test_log_cli_enabled_disabled(pytester: Pytester, enabled: bool) -> None:
msg = "critical message logged by test"
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
def test_log_cli():
@ -184,13 +185,13 @@ def test_log_cli_enabled_disabled(testdir, enabled):
)
)
if enabled:
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_cli=true
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
if enabled:
result.stdout.fnmatch_lines(
[
@ -204,9 +205,9 @@ def test_log_cli_enabled_disabled(testdir, enabled):
assert msg not in result.stdout.str()
def test_log_cli_default_level(testdir):
def test_log_cli_default_level(pytester: Pytester) -> None:
# Default log file level
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -217,14 +218,14 @@ def test_log_cli_default_level(testdir):
logging.getLogger('catchlog').warning("WARNING message will be shown")
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_cli=true
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
# fnmatch_lines does an assertion internally
result.stdout.fnmatch_lines(
@ -238,10 +239,12 @@ def test_log_cli_default_level(testdir):
assert result.ret == 0
def test_log_cli_default_level_multiple_tests(testdir, request):
def test_log_cli_default_level_multiple_tests(
pytester: Pytester, request: FixtureRequest
) -> None:
"""Ensure we reset the first newline added by the live logger between tests"""
filename = request.node.name + ".py"
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -252,14 +255,14 @@ def test_log_cli_default_level_multiple_tests(testdir, request):
logging.warning("log message from test_log_2")
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_cli=true
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(
[
f"{filename}::test_log_1 ",
@ -273,11 +276,13 @@ def test_log_cli_default_level_multiple_tests(testdir, request):
)
def test_log_cli_default_level_sections(testdir, request):
def test_log_cli_default_level_sections(
pytester: Pytester, request: FixtureRequest
) -> None:
"""Check that with live logging enable we are printing the correct headers during
start/setup/call/teardown/finish."""
filename = request.node.name + ".py"
testdir.makeconftest(
pytester.makeconftest(
"""
import pytest
import logging
@ -290,7 +295,7 @@ def test_log_cli_default_level_sections(testdir, request):
"""
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -308,14 +313,14 @@ def test_log_cli_default_level_sections(testdir, request):
logging.warning("log message from test_log_2")
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_cli=true
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(
[
f"{filename}::test_log_1 ",
@ -347,11 +352,13 @@ def test_log_cli_default_level_sections(testdir, request):
)
def test_live_logs_unknown_sections(testdir, request):
def test_live_logs_unknown_sections(
pytester: Pytester, request: FixtureRequest
) -> None:
"""Check that with live logging enable we are printing the correct headers during
start/setup/call/teardown/finish."""
filename = request.node.name + ".py"
testdir.makeconftest(
pytester.makeconftest(
"""
import pytest
import logging
@ -367,7 +374,7 @@ def test_live_logs_unknown_sections(testdir, request):
"""
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -383,14 +390,14 @@ def test_live_logs_unknown_sections(testdir, request):
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_cli=true
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(
[
"*WARNING*Unknown Section*",
@ -409,11 +416,13 @@ def test_live_logs_unknown_sections(testdir, request):
)
def test_sections_single_new_line_after_test_outcome(testdir, request):
def test_sections_single_new_line_after_test_outcome(
pytester: Pytester, request: FixtureRequest
) -> None:
"""Check that only a single new line is written between log messages during
teardown/finish."""
filename = request.node.name + ".py"
testdir.makeconftest(
pytester.makeconftest(
"""
import pytest
import logging
@ -427,7 +436,7 @@ def test_sections_single_new_line_after_test_outcome(testdir, request):
"""
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -443,14 +452,14 @@ def test_sections_single_new_line_after_test_outcome(testdir, request):
logging.warning("log message from test_log_1")
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_cli=true
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(
[
f"{filename}::test_log_1 ",
@ -487,9 +496,9 @@ def test_sections_single_new_line_after_test_outcome(testdir, request):
)
def test_log_cli_level(testdir):
def test_log_cli_level(pytester: Pytester) -> None:
# Default log file level
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -501,14 +510,14 @@ def test_log_cli_level(testdir):
print('PASSED')
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_cli=true
"""
)
result = testdir.runpytest("-s", "--log-cli-level=INFO")
result = pytester.runpytest("-s", "--log-cli-level=INFO")
# fnmatch_lines does an assertion internally
result.stdout.fnmatch_lines(
@ -522,7 +531,7 @@ def test_log_cli_level(testdir):
# make sure that that we get a '0' exit code for the testsuite
assert result.ret == 0
result = testdir.runpytest("-s", "--log-level=INFO")
result = pytester.runpytest("-s", "--log-level=INFO")
# fnmatch_lines does an assertion internally
result.stdout.fnmatch_lines(
@ -537,15 +546,15 @@ def test_log_cli_level(testdir):
assert result.ret == 0
def test_log_cli_ini_level(testdir):
testdir.makeini(
def test_log_cli_ini_level(pytester: Pytester) -> None:
pytester.makeini(
"""
[pytest]
log_cli=true
log_cli_level = INFO
"""
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -558,7 +567,7 @@ def test_log_cli_ini_level(testdir):
"""
)
result = testdir.runpytest("-s")
result = pytester.runpytest("-s")
# fnmatch_lines does an assertion internally
result.stdout.fnmatch_lines(
@ -577,11 +586,11 @@ def test_log_cli_ini_level(testdir):
"cli_args",
["", "--log-level=WARNING", "--log-file-level=WARNING", "--log-cli-level=WARNING"],
)
def test_log_cli_auto_enable(testdir, cli_args):
def test_log_cli_auto_enable(pytester: Pytester, cli_args: str) -> None:
"""Check that live logs are enabled if --log-level or --log-cli-level is passed on the CLI.
It should not be auto enabled if the same configs are set on the INI file.
"""
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -591,7 +600,7 @@ def test_log_cli_auto_enable(testdir, cli_args):
"""
)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_level=INFO
@ -599,7 +608,7 @@ def test_log_cli_auto_enable(testdir, cli_args):
"""
)
result = testdir.runpytest(cli_args)
result = pytester.runpytest(cli_args)
stdout = result.stdout.str()
if cli_args == "--log-cli-level=WARNING":
result.stdout.fnmatch_lines(
@ -620,9 +629,9 @@ def test_log_cli_auto_enable(testdir, cli_args):
assert "WARNING" not in stdout
def test_log_file_cli(testdir):
def test_log_file_cli(pytester: Pytester) -> None:
# Default log file level
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -635,9 +644,9 @@ def test_log_file_cli(testdir):
"""
)
log_file = testdir.tmpdir.join("pytest.log").strpath
log_file = str(pytester.path.joinpath("pytest.log"))
result = testdir.runpytest(
result = pytester.runpytest(
"-s", f"--log-file={log_file}", "--log-file-level=WARNING"
)
@ -653,9 +662,9 @@ def test_log_file_cli(testdir):
assert "This log message won't be shown" not in contents
def test_log_file_cli_level(testdir):
def test_log_file_cli_level(pytester: Pytester) -> None:
# Default log file level
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -668,9 +677,9 @@ def test_log_file_cli_level(testdir):
"""
)
log_file = testdir.tmpdir.join("pytest.log").strpath
log_file = str(pytester.path.joinpath("pytest.log"))
result = testdir.runpytest("-s", f"--log-file={log_file}", "--log-file-level=INFO")
result = pytester.runpytest("-s", f"--log-file={log_file}", "--log-file-level=INFO")
# fnmatch_lines does an assertion internally
result.stdout.fnmatch_lines(["test_log_file_cli_level.py PASSED"])
@ -684,22 +693,22 @@ def test_log_file_cli_level(testdir):
assert "This log message won't be shown" not in contents
def test_log_level_not_changed_by_default(testdir):
testdir.makepyfile(
def test_log_level_not_changed_by_default(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import logging
def test_log_file():
assert logging.getLogger().level == logging.WARNING
"""
)
result = testdir.runpytest("-s")
result = pytester.runpytest("-s")
result.stdout.fnmatch_lines(["* 1 passed in *"])
def test_log_file_ini(testdir):
log_file = testdir.tmpdir.join("pytest.log").strpath
def test_log_file_ini(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log"))
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_file={}
@ -708,7 +717,7 @@ def test_log_file_ini(testdir):
log_file
)
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -721,7 +730,7 @@ def test_log_file_ini(testdir):
"""
)
result = testdir.runpytest("-s")
result = pytester.runpytest("-s")
# fnmatch_lines does an assertion internally
result.stdout.fnmatch_lines(["test_log_file_ini.py PASSED"])
@ -735,10 +744,10 @@ def test_log_file_ini(testdir):
assert "This log message won't be shown" not in contents
def test_log_file_ini_level(testdir):
log_file = testdir.tmpdir.join("pytest.log").strpath
def test_log_file_ini_level(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log"))
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_file={}
@ -747,7 +756,7 @@ def test_log_file_ini_level(testdir):
log_file
)
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import logging
@ -760,7 +769,7 @@ def test_log_file_ini_level(testdir):
"""
)
result = testdir.runpytest("-s")
result = pytester.runpytest("-s")
# fnmatch_lines does an assertion internally
result.stdout.fnmatch_lines(["test_log_file_ini_level.py PASSED"])
@ -774,10 +783,10 @@ def test_log_file_ini_level(testdir):
assert "This log message won't be shown" not in contents
def test_log_file_unicode(testdir):
log_file = testdir.tmpdir.join("pytest.log").strpath
def test_log_file_unicode(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log"))
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_file={}
@ -786,7 +795,7 @@ def test_log_file_unicode(testdir):
log_file
)
)
testdir.makepyfile(
pytester.makepyfile(
"""\
import logging
@ -797,7 +806,7 @@ def test_log_file_unicode(testdir):
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
# make sure that that we get a '0' exit code for the testsuite
assert result.ret == 0
@ -810,11 +819,13 @@ def test_log_file_unicode(testdir):
@pytest.mark.parametrize("has_capture_manager", [True, False])
def test_live_logging_suspends_capture(has_capture_manager: bool, request) -> None:
def test_live_logging_suspends_capture(
has_capture_manager: bool, request: FixtureRequest
) -> None:
"""Test that capture manager is suspended when we emitting messages for live logging.
This tests the implementation calls instead of behavior because it is difficult/impossible to do it using
``testdir`` facilities because they do their own capturing.
``pytester`` facilities because they do their own capturing.
We parametrize the test to also make sure _LiveLoggingStreamHandler works correctly if no capture manager plugin
is installed.
@ -856,8 +867,8 @@ def test_live_logging_suspends_capture(has_capture_manager: bool, request) -> No
assert cast(io.StringIO, out_file).getvalue() == "\nsome message\n"
def test_collection_live_logging(testdir):
testdir.makepyfile(
def test_collection_live_logging(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import logging
@ -865,22 +876,22 @@ def test_collection_live_logging(testdir):
"""
)
result = testdir.runpytest("--log-cli-level=INFO")
result = pytester.runpytest("--log-cli-level=INFO")
result.stdout.fnmatch_lines(
["*--- live log collection ---*", "*Normal message*", "collected 0 items"]
)
@pytest.mark.parametrize("verbose", ["", "-q", "-qq"])
def test_collection_collect_only_live_logging(testdir, verbose):
testdir.makepyfile(
def test_collection_collect_only_live_logging(pytester: Pytester, verbose: str) -> None:
pytester.makepyfile(
"""
def test_simple():
pass
"""
)
result = testdir.runpytest("--collect-only", "--log-cli-level=INFO", verbose)
result = pytester.runpytest("--collect-only", "--log-cli-level=INFO", verbose)
expected_lines = []
@ -907,10 +918,10 @@ def test_collection_collect_only_live_logging(testdir, verbose):
result.stdout.fnmatch_lines(expected_lines)
def test_collection_logging_to_file(testdir):
log_file = testdir.tmpdir.join("pytest.log").strpath
def test_collection_logging_to_file(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log"))
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_file={}
@ -920,7 +931,7 @@ def test_collection_logging_to_file(testdir):
)
)
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -932,7 +943,7 @@ def test_collection_logging_to_file(testdir):
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.no_fnmatch_line("*--- live log collection ---*")
@ -945,10 +956,10 @@ def test_collection_logging_to_file(testdir):
assert "info message in test_simple" in contents
def test_log_in_hooks(testdir):
log_file = testdir.tmpdir.join("pytest.log").strpath
def test_log_in_hooks(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log"))
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_file={}
@ -958,7 +969,7 @@ def test_log_in_hooks(testdir):
log_file
)
)
testdir.makeconftest(
pytester.makeconftest(
"""
import logging
@ -972,7 +983,7 @@ def test_log_in_hooks(testdir):
logging.info('sessionfinish')
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*sessionstart*", "*runtestloop*", "*sessionfinish*"])
with open(log_file) as rfh:
contents = rfh.read()
@ -981,10 +992,10 @@ def test_log_in_hooks(testdir):
assert "sessionfinish" in contents
def test_log_in_runtest_logreport(testdir):
log_file = testdir.tmpdir.join("pytest.log").strpath
def test_log_in_runtest_logreport(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log"))
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_file={}
@ -994,7 +1005,7 @@ def test_log_in_runtest_logreport(testdir):
log_file
)
)
testdir.makeconftest(
pytester.makeconftest(
"""
import logging
logger = logging.getLogger(__name__)
@ -1003,29 +1014,29 @@ def test_log_in_runtest_logreport(testdir):
logger.info("logreport")
"""
)
testdir.makepyfile(
pytester.makepyfile(
"""
def test_first():
assert True
"""
)
testdir.runpytest()
pytester.runpytest()
with open(log_file) as rfh:
contents = rfh.read()
assert contents.count("logreport") == 3
def test_log_set_path(testdir):
report_dir_base = testdir.tmpdir.strpath
def test_log_set_path(pytester: Pytester) -> None:
report_dir_base = str(pytester.path)
testdir.makeini(
pytester.makeini(
"""
[pytest]
log_file_level = DEBUG
log_cli=true
"""
)
testdir.makeconftest(
pytester.makeconftest(
"""
import os
import pytest
@ -1040,7 +1051,7 @@ def test_log_set_path(testdir):
repr(report_dir_base)
)
)
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
logger = logging.getLogger("testcase-logger")
@ -1053,7 +1064,7 @@ def test_log_set_path(testdir):
assert True
"""
)
testdir.runpytest()
pytester.runpytest()
with open(os.path.join(report_dir_base, "test_first")) as rfh:
content = rfh.read()
assert "message from test 1" in content
@ -1063,10 +1074,10 @@ def test_log_set_path(testdir):
assert "message from test 2" in content
def test_colored_captured_log(testdir):
def test_colored_captured_log(pytester: Pytester) -> None:
"""Test that the level names of captured log messages of a failing test
are colored."""
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -1077,7 +1088,7 @@ def test_colored_captured_log(testdir):
assert False
"""
)
result = testdir.runpytest("--log-level=INFO", "--color=yes")
result = pytester.runpytest("--log-level=INFO", "--color=yes")
assert result.ret == 1
result.stdout.fnmatch_lines(
[
@ -1087,9 +1098,9 @@ def test_colored_captured_log(testdir):
)
def test_colored_ansi_esc_caplogtext(testdir):
def test_colored_ansi_esc_caplogtext(pytester: Pytester) -> None:
"""Make sure that caplog.text does not contain ANSI escape sequences."""
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -1100,11 +1111,11 @@ def test_colored_ansi_esc_caplogtext(testdir):
assert '\x1b' not in caplog.text
"""
)
result = testdir.runpytest("--log-level=INFO", "--color=yes")
result = pytester.runpytest("--log-level=INFO", "--color=yes")
assert result.ret == 0
def test_logging_emit_error(testdir: Testdir) -> None:
def test_logging_emit_error(pytester: Pytester) -> None:
"""An exception raised during emit() should fail the test.
The default behavior of logging is to print "Logging error"
@ -1112,7 +1123,7 @@ def test_logging_emit_error(testdir: Testdir) -> None:
pytest overrides this behavior to propagate the exception.
"""
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -1120,7 +1131,7 @@ def test_logging_emit_error(testdir: Testdir) -> None:
logging.warning('oops', 'first', 2)
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.assert_outcomes(failed=1)
result.stdout.fnmatch_lines(
[
@ -1130,10 +1141,10 @@ def test_logging_emit_error(testdir: Testdir) -> None:
)
def test_logging_emit_error_supressed(testdir: Testdir) -> None:
def test_logging_emit_error_supressed(pytester: Pytester) -> None:
"""If logging is configured to silently ignore errors, pytest
doesn't propagate errors either."""
testdir.makepyfile(
pytester.makepyfile(
"""
import logging
@ -1142,13 +1153,15 @@ def test_logging_emit_error_supressed(testdir: Testdir) -> None:
logging.warning('oops', 'first', 2)
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.assert_outcomes(passed=1)
def test_log_file_cli_subdirectories_are_successfully_created(testdir):
path = testdir.makepyfile(""" def test_logger(): pass """)
def test_log_file_cli_subdirectories_are_successfully_created(
pytester: Pytester,
) -> None:
path = pytester.makepyfile(""" def test_logger(): pass """)
expected = os.path.join(os.path.dirname(str(path)), "foo", "bar")
result = testdir.runpytest("--log-file=foo/bar/logf.log")
result = pytester.runpytest("--log-file=foo/bar/logf.log")
assert "logf.log" in os.listdir(expected)
assert result.ret == ExitCode.OK

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,6 @@ from typing import Generator
from typing import List
from typing import Optional
import py
import pytest
from _pytest.config import ExitCode
from _pytest.config import PytestPluginManager
@ -93,9 +91,9 @@ class TestConftestValueAccessGlobal:
conftest = ConftestWithSetinitial(startdir)
mod, value = conftest._rget_with_confmod("a", startdir, importmode="prepend")
assert value == 1.5
path = py.path.local(mod.__file__)
assert path.dirpath() == basedir / "adir" / "b"
assert path.purebasename.startswith("conftest")
path = Path(mod.__file__)
assert path.parent == basedir / "adir" / "b"
assert path.stem == "conftest"
def test_conftest_in_nonpkg_with_init(tmp_path: Path, _sys_snapshot) -> None:
@ -361,11 +359,10 @@ def test_conftest_import_order(pytester: Pytester, monkeypatch: MonkeyPatch) ->
def test_fixture_dependency(pytester: Pytester) -> None:
ct1 = pytester.makeconftest("")
ct1 = pytester.makepyfile("__init__.py")
ct1.write_text("")
pytester.makeconftest("")
pytester.path.joinpath("__init__.py").touch()
sub = pytester.mkdir("sub")
sub.joinpath("__init__.py").write_text("")
sub.joinpath("__init__.py").touch()
sub.joinpath("conftest.py").write_text(
textwrap.dedent(
"""\
@ -387,7 +384,7 @@ def test_fixture_dependency(pytester: Pytester) -> None:
)
subsub = sub.joinpath("subsub")
subsub.mkdir()
subsub.joinpath("__init__.py").write_text("")
subsub.joinpath("__init__.py").touch()
subsub.joinpath("test_bar.py").write_text(
textwrap.dedent(
"""\
@ -525,8 +522,8 @@ class TestConftestVisibility:
"""#616"""
dirs = self._setup_tree(pytester)
print("pytest run in cwd: %s" % (dirs[chdir].relative_to(pytester.path)))
print("pytestarg : %s" % (testarg))
print("expected pass : %s" % (expect_ntests_passed))
print("pytestarg : %s" % testarg)
print("expected pass : %s" % expect_ntests_passed)
os.chdir(dirs[chdir])
reprec = pytester.inline_run(testarg, "-q", "--traceconfig")
reprec.assertoutcome(passed=expect_ntests_passed)

View File

@ -2,15 +2,14 @@ import os
import re
import sys
import textwrap
from pathlib import Path
from typing import Dict
from typing import Generator
from typing import Type
import py
import pytest
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pytester import Testdir
from _pytest.pytester import Pytester
@pytest.fixture
@ -233,8 +232,8 @@ def test_setenv_prepend() -> None:
assert "XYZ123" not in os.environ
def test_monkeypatch_plugin(testdir: Testdir) -> None:
reprec = testdir.inline_runsource(
def test_monkeypatch_plugin(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
def test_method(monkeypatch):
assert monkeypatch.__class__.__name__ == "MonkeyPatch"
@ -268,33 +267,33 @@ def test_syspath_prepend_double_undo(mp: MonkeyPatch) -> None:
sys.path[:] = old_syspath
def test_chdir_with_path_local(mp: MonkeyPatch, tmpdir: py.path.local) -> None:
mp.chdir(tmpdir)
assert os.getcwd() == tmpdir.strpath
def test_chdir_with_path_local(mp: MonkeyPatch, tmp_path: Path) -> None:
mp.chdir(tmp_path)
assert os.getcwd() == str(tmp_path)
def test_chdir_with_str(mp: MonkeyPatch, tmpdir: py.path.local) -> None:
mp.chdir(tmpdir.strpath)
assert os.getcwd() == tmpdir.strpath
def test_chdir_with_str(mp: MonkeyPatch, tmp_path: Path) -> None:
mp.chdir(str(tmp_path))
assert os.getcwd() == str(tmp_path)
def test_chdir_undo(mp: MonkeyPatch, tmpdir: py.path.local) -> None:
def test_chdir_undo(mp: MonkeyPatch, tmp_path: Path) -> None:
cwd = os.getcwd()
mp.chdir(tmpdir)
mp.chdir(tmp_path)
mp.undo()
assert os.getcwd() == cwd
def test_chdir_double_undo(mp: MonkeyPatch, tmpdir: py.path.local) -> None:
mp.chdir(tmpdir.strpath)
def test_chdir_double_undo(mp: MonkeyPatch, tmp_path: Path) -> None:
mp.chdir(str(tmp_path))
mp.undo()
tmpdir.chdir()
os.chdir(tmp_path)
mp.undo()
assert os.getcwd() == tmpdir.strpath
assert os.getcwd() == str(tmp_path)
def test_issue185_time_breaks(testdir: Testdir) -> None:
testdir.makepyfile(
def test_issue185_time_breaks(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import time
def test_m(monkeypatch):
@ -303,7 +302,7 @@ def test_issue185_time_breaks(testdir: Testdir) -> None:
monkeypatch.setattr(time, "time", f)
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(
"""
*1 passed*
@ -311,9 +310,9 @@ def test_issue185_time_breaks(testdir: Testdir) -> None:
)
def test_importerror(testdir: Testdir) -> None:
p = testdir.mkpydir("package")
p.join("a.py").write(
def test_importerror(pytester: Pytester) -> None:
p = pytester.mkpydir("package")
p.joinpath("a.py").write_text(
textwrap.dedent(
"""\
import doesnotexist
@ -322,7 +321,7 @@ def test_importerror(testdir: Testdir) -> None:
"""
)
)
testdir.tmpdir.join("test_importerror.py").write(
pytester.path.joinpath("test_importerror.py").write_text(
textwrap.dedent(
"""\
def test_importerror(monkeypatch):
@ -330,7 +329,7 @@ def test_importerror(testdir: Testdir) -> None:
"""
)
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(
"""
*import error in package.a: No module named 'doesnotexist'*
@ -420,16 +419,18 @@ def test_context_classmethod() -> None:
def test_syspath_prepend_with_namespace_packages(
testdir: Testdir, monkeypatch: MonkeyPatch
pytester: Pytester, monkeypatch: MonkeyPatch
) -> None:
for dirname in "hello", "world":
d = testdir.mkdir(dirname)
ns = d.mkdir("ns_pkg")
ns.join("__init__.py").write(
d = pytester.mkdir(dirname)
ns = d.joinpath("ns_pkg")
ns.mkdir()
ns.joinpath("__init__.py").write_text(
"__import__('pkg_resources').declare_namespace(__name__)"
)
lib = ns.mkdir(dirname)
lib.join("__init__.py").write("def check(): return %r" % dirname)
lib = ns.joinpath(dirname)
lib.mkdir()
lib.joinpath("__init__.py").write_text("def check(): return %r" % dirname)
monkeypatch.syspath_prepend("hello")
import ns_pkg.hello
@ -446,8 +447,7 @@ def test_syspath_prepend_with_namespace_packages(
assert ns_pkg.world.check() == "world"
# Should invalidate caches via importlib.invalidate_caches.
tmpdir = testdir.tmpdir
modules_tmpdir = tmpdir.mkdir("modules_tmpdir")
modules_tmpdir = pytester.mkdir("modules_tmpdir")
monkeypatch.syspath_prepend(str(modules_tmpdir))
modules_tmpdir.join("main_app.py").write("app = True")
modules_tmpdir.joinpath("main_app.py").write_text("app = True")
from main_app import app # noqa: F401

View File

@ -1,13 +1,17 @@
import os
import shutil
import sys
import types
from typing import List
import pytest
from _pytest.config import Config
from _pytest.config import ExitCode
from _pytest.config import PytestPluginManager
from _pytest.config.exceptions import UsageError
from _pytest.main import Session
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pathlib import import_path
from _pytest.pytester import Pytester
@ -18,7 +22,7 @@ def pytestpm() -> PytestPluginManager:
class TestPytestPluginInteractions:
def test_addhooks_conftestplugin(
self, pytester: Pytester, _config_for_test
self, pytester: Pytester, _config_for_test: Config
) -> None:
pytester.makepyfile(
newhooks="""
@ -45,15 +49,15 @@ class TestPytestPluginInteractions:
res = config.hook.pytest_myhook(xyz=10)
assert res == [11]
def test_addhooks_nohooks(self, testdir):
testdir.makeconftest(
def test_addhooks_nohooks(self, pytester: Pytester) -> None:
pytester.makeconftest(
"""
import sys
def pytest_addhooks(pluginmanager):
pluginmanager.add_hookspecs(sys)
"""
)
res = testdir.runpytest()
res = pytester.runpytest()
assert res.ret != 0
res.stderr.fnmatch_lines(["*did not find*sys*"])
@ -70,8 +74,8 @@ class TestPytestPluginInteractions:
config.pluginmanager._importconftest(p, importmode="prepend")
assert config.option.test123
def test_configure(self, testdir):
config = testdir.parseconfig()
def test_configure(self, pytester: Pytester) -> None:
config = pytester.parseconfig()
values = []
class A:
@ -90,7 +94,7 @@ class TestPytestPluginInteractions:
config.pluginmanager.register(A())
assert len(values) == 2
def test_hook_tracing(self, _config_for_test) -> None:
def test_hook_tracing(self, _config_for_test: Config) -> None:
pytestpm = _config_for_test.pluginmanager # fully initialized with plugins
saveindent = []
@ -139,9 +143,9 @@ class TestPytestPluginInteractions:
ihook_b = session.gethookproxy(pytester.path / "tests")
assert ihook_a is not ihook_b
def test_hook_with_addoption(self, testdir):
def test_hook_with_addoption(self, pytester: Pytester) -> None:
"""Test that hooks can be used in a call to pytest_addoption"""
testdir.makepyfile(
pytester.makepyfile(
newhooks="""
import pytest
@pytest.hookspec(firstresult=True)
@ -149,7 +153,7 @@ class TestPytestPluginInteractions:
pass
"""
)
testdir.makepyfile(
pytester.makepyfile(
myplugin="""
import newhooks
def pytest_addhooks(pluginmanager):
@ -159,30 +163,32 @@ class TestPytestPluginInteractions:
parser.addoption("--config", help="Config, defaults to %(default)s", default=default_value)
"""
)
testdir.makeconftest(
pytester.makeconftest(
"""
pytest_plugins=("myplugin",)
def pytest_default_value():
return "default_value"
"""
)
res = testdir.runpytest("--help")
res = pytester.runpytest("--help")
res.stdout.fnmatch_lines(["*--config=CONFIG*default_value*"])
def test_default_markers(testdir):
result = testdir.runpytest("--markers")
def test_default_markers(pytester: Pytester) -> None:
result = pytester.runpytest("--markers")
result.stdout.fnmatch_lines(["*tryfirst*first*", "*trylast*last*"])
def test_importplugin_error_message(testdir, pytestpm):
def test_importplugin_error_message(
pytester: Pytester, pytestpm: PytestPluginManager
) -> None:
"""Don't hide import errors when importing plugins and provide
an easy to debug message.
See #375 and #1998.
"""
testdir.syspathinsert(testdir.tmpdir)
testdir.makepyfile(
pytester.syspathinsert(pytester.path)
pytester.makepyfile(
qwe="""\
def test_traceback():
raise ImportError('Not possible to import: ☺')
@ -199,7 +205,7 @@ def test_importplugin_error_message(testdir, pytestpm):
class TestPytestPluginManager:
def test_register_imported_modules(self):
def test_register_imported_modules(self) -> None:
pm = PytestPluginManager()
mod = types.ModuleType("x.y.pytest_hello")
pm.register(mod)
@ -219,23 +225,27 @@ class TestPytestPluginManager:
assert pm.get_plugin("pytest_xyz") == mod
assert pm.is_registered(mod)
def test_consider_module(self, testdir, pytestpm: PytestPluginManager) -> None:
testdir.syspathinsert()
testdir.makepyfile(pytest_p1="#")
testdir.makepyfile(pytest_p2="#")
def test_consider_module(
self, pytester: Pytester, pytestpm: PytestPluginManager
) -> None:
pytester.syspathinsert()
pytester.makepyfile(pytest_p1="#")
pytester.makepyfile(pytest_p2="#")
mod = types.ModuleType("temp")
mod.__dict__["pytest_plugins"] = ["pytest_p1", "pytest_p2"]
pytestpm.consider_module(mod)
assert pytestpm.get_plugin("pytest_p1").__name__ == "pytest_p1"
assert pytestpm.get_plugin("pytest_p2").__name__ == "pytest_p2"
def test_consider_module_import_module(self, testdir, _config_for_test) -> None:
def test_consider_module_import_module(
self, pytester: Pytester, _config_for_test: Config
) -> None:
pytestpm = _config_for_test.pluginmanager
mod = types.ModuleType("x")
mod.__dict__["pytest_plugins"] = "pytest_a"
aplugin = testdir.makepyfile(pytest_a="#")
reprec = testdir.make_hook_recorder(pytestpm)
testdir.syspathinsert(aplugin.dirpath())
aplugin = pytester.makepyfile(pytest_a="#")
reprec = pytester.make_hook_recorder(pytestpm)
pytester.syspathinsert(aplugin.parent)
pytestpm.consider_module(mod)
call = reprec.getcall(pytestpm.hook.pytest_plugin_registered.name)
assert call.plugin.__name__ == "pytest_a"
@ -245,30 +255,37 @@ class TestPytestPluginManager:
values = reprec.getcalls("pytest_plugin_registered")
assert len(values) == 1
def test_consider_env_fails_to_import(self, monkeypatch, pytestpm):
def test_consider_env_fails_to_import(
self, monkeypatch: MonkeyPatch, pytestpm: PytestPluginManager
) -> None:
monkeypatch.setenv("PYTEST_PLUGINS", "nonexisting", prepend=",")
with pytest.raises(ImportError):
pytestpm.consider_env()
@pytest.mark.filterwarnings("always")
def test_plugin_skip(self, testdir, monkeypatch):
p = testdir.makepyfile(
def test_plugin_skip(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
p = pytester.makepyfile(
skipping1="""
import pytest
pytest.skip("hello", allow_module_level=True)
"""
)
p.copy(p.dirpath("skipping2.py"))
shutil.copy(p, p.with_name("skipping2.py"))
monkeypatch.setenv("PYTEST_PLUGINS", "skipping2")
result = testdir.runpytest("-p", "skipping1", syspathinsert=True)
result = pytester.runpytest("-p", "skipping1", syspathinsert=True)
assert result.ret == ExitCode.NO_TESTS_COLLECTED
result.stdout.fnmatch_lines(
["*skipped plugin*skipping1*hello*", "*skipped plugin*skipping2*hello*"]
)
def test_consider_env_plugin_instantiation(self, testdir, monkeypatch, pytestpm):
testdir.syspathinsert()
testdir.makepyfile(xy123="#")
def test_consider_env_plugin_instantiation(
self,
pytester: Pytester,
monkeypatch: MonkeyPatch,
pytestpm: PytestPluginManager,
) -> None:
pytester.syspathinsert()
pytester.makepyfile(xy123="#")
monkeypatch.setitem(os.environ, "PYTEST_PLUGINS", "xy123")
l1 = len(pytestpm.get_plugins())
pytestpm.consider_env()
@ -279,9 +296,11 @@ class TestPytestPluginManager:
l3 = len(pytestpm.get_plugins())
assert l2 == l3
def test_pluginmanager_ENV_startup(self, testdir, monkeypatch):
testdir.makepyfile(pytest_x500="#")
p = testdir.makepyfile(
def test_pluginmanager_ENV_startup(
self, pytester: Pytester, monkeypatch: MonkeyPatch
) -> None:
pytester.makepyfile(pytest_x500="#")
p = pytester.makepyfile(
"""
import pytest
def test_hello(pytestconfig):
@ -290,17 +309,19 @@ class TestPytestPluginManager:
"""
)
monkeypatch.setenv("PYTEST_PLUGINS", "pytest_x500", prepend=",")
result = testdir.runpytest(p, syspathinsert=True)
result = pytester.runpytest(p, syspathinsert=True)
assert result.ret == 0
result.stdout.fnmatch_lines(["*1 passed*"])
def test_import_plugin_importname(self, testdir, pytestpm):
def test_import_plugin_importname(
self, pytester: Pytester, pytestpm: PytestPluginManager
) -> None:
pytest.raises(ImportError, pytestpm.import_plugin, "qweqwex.y")
pytest.raises(ImportError, pytestpm.import_plugin, "pytest_qweqwx.y")
testdir.syspathinsert()
pytester.syspathinsert()
pluginname = "pytest_hello"
testdir.makepyfile(**{pluginname: ""})
pytester.makepyfile(**{pluginname: ""})
pytestpm.import_plugin("pytest_hello")
len1 = len(pytestpm.get_plugins())
pytestpm.import_plugin("pytest_hello")
@ -311,25 +332,29 @@ class TestPytestPluginManager:
plugin2 = pytestpm.get_plugin("pytest_hello")
assert plugin2 is plugin1
def test_import_plugin_dotted_name(self, testdir, pytestpm):
def test_import_plugin_dotted_name(
self, pytester: Pytester, pytestpm: PytestPluginManager
) -> None:
pytest.raises(ImportError, pytestpm.import_plugin, "qweqwex.y")
pytest.raises(ImportError, pytestpm.import_plugin, "pytest_qweqwex.y")
testdir.syspathinsert()
testdir.mkpydir("pkg").join("plug.py").write("x=3")
pytester.syspathinsert()
pytester.mkpydir("pkg").joinpath("plug.py").write_text("x=3")
pluginname = "pkg.plug"
pytestpm.import_plugin(pluginname)
mod = pytestpm.get_plugin("pkg.plug")
assert mod.x == 3
def test_consider_conftest_deps(self, testdir, pytestpm):
mod = testdir.makepyfile("pytest_plugins='xyz'").pyimport()
def test_consider_conftest_deps(
self, pytester: Pytester, pytestpm: PytestPluginManager,
) -> None:
mod = import_path(pytester.makepyfile("pytest_plugins='xyz'"))
with pytest.raises(ImportError):
pytestpm.consider_conftest(mod)
class TestPytestPluginManagerBootstrapming:
def test_preparse_args(self, pytestpm):
def test_preparse_args(self, pytestpm: PytestPluginManager) -> None:
pytest.raises(
ImportError, lambda: pytestpm.consider_preparse(["xyz", "-p", "hello123"])
)
@ -346,7 +371,7 @@ class TestPytestPluginManagerBootstrapming:
with pytest.raises(UsageError, match="^plugin main cannot be disabled$"):
pytestpm.consider_preparse(["-p", "no:main"])
def test_plugin_prevent_register(self, pytestpm):
def test_plugin_prevent_register(self, pytestpm: PytestPluginManager) -> None:
pytestpm.consider_preparse(["xyz", "-p", "no:abc"])
l1 = pytestpm.get_plugins()
pytestpm.register(42, name="abc")
@ -354,7 +379,9 @@ class TestPytestPluginManagerBootstrapming:
assert len(l2) == len(l1)
assert 42 not in l2
def test_plugin_prevent_register_unregistered_alredy_registered(self, pytestpm):
def test_plugin_prevent_register_unregistered_alredy_registered(
self, pytestpm: PytestPluginManager
) -> None:
pytestpm.register(42, name="abc")
l1 = pytestpm.get_plugins()
assert 42 in l1
@ -363,8 +390,8 @@ class TestPytestPluginManagerBootstrapming:
assert 42 not in l2
def test_plugin_prevent_register_stepwise_on_cacheprovider_unregister(
self, pytestpm
):
self, pytestpm: PytestPluginManager
) -> None:
"""From PR #4304: The only way to unregister a module is documented at
the end of https://docs.pytest.org/en/stable/plugins.html.
@ -380,7 +407,7 @@ class TestPytestPluginManagerBootstrapming:
assert 42 not in l2
assert 43 not in l2
def test_blocked_plugin_can_be_used(self, pytestpm):
def test_blocked_plugin_can_be_used(self, pytestpm: PytestPluginManager) -> None:
pytestpm.consider_preparse(["xyz", "-p", "no:abc", "-p", "abc"])
assert pytestpm.has_plugin("abc")

View File

@ -1,29 +1,30 @@
from pathlib import Path
from typing import Sequence
from typing import Union
import py.path
import pytest
from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionRepr
from _pytest.config import Config
from _pytest.pytester import Testdir
from _pytest.pytester import Pytester
from _pytest.reports import CollectReport
from _pytest.reports import TestReport
class TestReportSerialization:
def test_xdist_longrepr_to_str_issue_241(self, testdir: Testdir) -> None:
def test_xdist_longrepr_to_str_issue_241(self, pytester: Pytester) -> None:
"""Regarding issue pytest-xdist#241.
This test came originally from test_remote.py in xdist (ca03269).
"""
testdir.makepyfile(
pytester.makepyfile(
"""
def test_a(): assert False
def test_b(): pass
"""
)
reprec = testdir.inline_run()
reprec = pytester.inline_run()
reports = reprec.getreports("pytest_runtest_logreport")
assert len(reports) == 6
test_a_call = reports[1]
@ -35,12 +36,12 @@ class TestReportSerialization:
assert test_b_call.outcome == "passed"
assert test_b_call._to_json()["longrepr"] is None
def test_xdist_report_longrepr_reprcrash_130(self, testdir: Testdir) -> None:
def test_xdist_report_longrepr_reprcrash_130(self, pytester: Pytester) -> None:
"""Regarding issue pytest-xdist#130
This test came originally from test_remote.py in xdist (ca03269).
"""
reprec = testdir.inline_runsource(
reprec = pytester.inline_runsource(
"""
def test_fail():
assert False, 'Expected Message'
@ -74,14 +75,14 @@ class TestReportSerialization:
# Missing section attribute PR171
assert added_section in a.longrepr.sections
def test_reprentries_serialization_170(self, testdir: Testdir) -> None:
def test_reprentries_serialization_170(self, pytester: Pytester) -> None:
"""Regarding issue pytest-xdist#170
This test came originally from test_remote.py in xdist (ca03269).
"""
from _pytest._code.code import ReprEntry
reprec = testdir.inline_runsource(
reprec = pytester.inline_runsource(
"""
def test_repr_entry():
x = 0
@ -120,14 +121,14 @@ class TestReportSerialization:
assert rep_entry.reprlocals.lines == a_entry.reprlocals.lines
assert rep_entry.style == a_entry.style
def test_reprentries_serialization_196(self, testdir: Testdir) -> None:
def test_reprentries_serialization_196(self, pytester: Pytester) -> None:
"""Regarding issue pytest-xdist#196
This test came originally from test_remote.py in xdist (ca03269).
"""
from _pytest._code.code import ReprEntryNative
reprec = testdir.inline_runsource(
reprec = pytester.inline_runsource(
"""
def test_repr_entry_native():
x = 0
@ -149,9 +150,9 @@ class TestReportSerialization:
assert isinstance(rep_entries[i], ReprEntryNative)
assert rep_entries[i].lines == a_entries[i].lines
def test_itemreport_outcomes(self, testdir: Testdir) -> None:
def test_itemreport_outcomes(self, pytester: Pytester) -> None:
# This test came originally from test_remote.py in xdist (ca03269).
reprec = testdir.inline_runsource(
reprec = pytester.inline_runsource(
"""
import pytest
def test_pass(): pass
@ -183,9 +184,9 @@ class TestReportSerialization:
if rep.failed:
assert newrep.longreprtext == rep.longreprtext
def test_collectreport_passed(self, testdir: Testdir) -> None:
def test_collectreport_passed(self, pytester: Pytester) -> None:
"""This test came originally from test_remote.py in xdist (ca03269)."""
reprec = testdir.inline_runsource("def test_func(): pass")
reprec = pytester.inline_runsource("def test_func(): pass")
reports = reprec.getreports("pytest_collectreport")
for rep in reports:
d = rep._to_json()
@ -194,9 +195,9 @@ class TestReportSerialization:
assert newrep.failed == rep.failed
assert newrep.skipped == rep.skipped
def test_collectreport_fail(self, testdir: Testdir) -> None:
def test_collectreport_fail(self, pytester: Pytester) -> None:
"""This test came originally from test_remote.py in xdist (ca03269)."""
reprec = testdir.inline_runsource("qwe abc")
reprec = pytester.inline_runsource("qwe abc")
reports = reprec.getreports("pytest_collectreport")
assert reports
for rep in reports:
@ -208,9 +209,9 @@ class TestReportSerialization:
if rep.failed:
assert newrep.longrepr == str(rep.longrepr)
def test_extended_report_deserialization(self, testdir: Testdir) -> None:
def test_extended_report_deserialization(self, pytester: Pytester) -> None:
"""This test came originally from test_remote.py in xdist (ca03269)."""
reprec = testdir.inline_runsource("qwe abc")
reprec = pytester.inline_runsource("qwe abc")
reports = reprec.getreports("pytest_collectreport")
assert reports
for rep in reports:
@ -224,33 +225,33 @@ class TestReportSerialization:
if rep.failed:
assert newrep.longrepr == str(rep.longrepr)
def test_paths_support(self, testdir: Testdir) -> None:
def test_paths_support(self, pytester: Pytester) -> None:
"""Report attributes which are py.path or pathlib objects should become strings."""
testdir.makepyfile(
pytester.makepyfile(
"""
def test_a():
assert False
"""
)
reprec = testdir.inline_run()
reprec = pytester.inline_run()
reports = reprec.getreports("pytest_runtest_logreport")
assert len(reports) == 3
test_a_call = reports[1]
test_a_call.path1 = testdir.tmpdir # type: ignore[attr-defined]
test_a_call.path2 = Path(testdir.tmpdir) # type: ignore[attr-defined]
test_a_call.path1 = py.path.local(pytester.path) # type: ignore[attr-defined]
test_a_call.path2 = pytester.path # type: ignore[attr-defined]
data = test_a_call._to_json()
assert data["path1"] == str(testdir.tmpdir)
assert data["path2"] == str(testdir.tmpdir)
assert data["path1"] == str(pytester.path)
assert data["path2"] == str(pytester.path)
def test_deserialization_failure(self, testdir: Testdir) -> None:
def test_deserialization_failure(self, pytester: Pytester) -> None:
"""Check handling of failure during deserialization of report types."""
testdir.makepyfile(
pytester.makepyfile(
"""
def test_a():
assert False
"""
)
reprec = testdir.inline_run()
reprec = pytester.inline_run()
reports = reprec.getreports("pytest_runtest_logreport")
assert len(reports) == 3
test_a_call = reports[1]
@ -265,9 +266,11 @@ class TestReportSerialization:
TestReport._from_json(data)
@pytest.mark.parametrize("report_class", [TestReport, CollectReport])
def test_chained_exceptions(self, testdir: Testdir, tw_mock, report_class) -> None:
def test_chained_exceptions(
self, pytester: Pytester, tw_mock, report_class
) -> None:
"""Check serialization/deserialization of report objects containing chained exceptions (#5786)"""
testdir.makepyfile(
pytester.makepyfile(
"""
def foo():
raise ValueError('value error')
@ -283,7 +286,7 @@ class TestReportSerialization:
)
)
reprec = testdir.inline_run()
reprec = pytester.inline_run()
if report_class is TestReport:
reports: Union[
Sequence[TestReport], Sequence[CollectReport]
@ -338,14 +341,14 @@ class TestReportSerialization:
# elsewhere and we do check the contents of the longrepr object after loading it.
loaded_report.longrepr.toterminal(tw_mock)
def test_chained_exceptions_no_reprcrash(self, testdir: Testdir, tw_mock) -> None:
def test_chained_exceptions_no_reprcrash(self, pytester: Pytester, tw_mock) -> None:
"""Regression test for tracebacks without a reprcrash (#5971)
This happens notably on exceptions raised by multiprocess.pool: the exception transfer
from subprocess to main process creates an artificial exception, which ExceptionInfo
can't obtain the ReprFileLocation from.
"""
testdir.makepyfile(
pytester.makepyfile(
"""
from concurrent.futures import ProcessPoolExecutor
@ -358,8 +361,8 @@ class TestReportSerialization:
"""
)
testdir.syspathinsert()
reprec = testdir.inline_run()
pytester.syspathinsert()
reprec = pytester.inline_run()
reports = reprec.getreports("pytest_runtest_logreport")
@ -396,12 +399,13 @@ class TestReportSerialization:
loaded_report.longrepr.toterminal(tw_mock)
def test_report_prevent_ConftestImportFailure_hiding_exception(
self, testdir: Testdir
self, pytester: Pytester
) -> None:
sub_dir = testdir.tmpdir.join("ns").ensure_dir()
sub_dir.join("conftest").new(ext=".py").write("import unknown")
sub_dir = pytester.path.joinpath("ns")
sub_dir.mkdir()
sub_dir.joinpath("conftest.py").write_text("import unknown")
result = testdir.runpytest_subprocess(".")
result = pytester.runpytest_subprocess(".")
result.stdout.fnmatch_lines(["E *Error: No module named 'unknown'"])
result.stdout.no_fnmatch_line("ERROR - *ConftestImportFailure*")
@ -409,14 +413,14 @@ class TestReportSerialization:
class TestHooks:
"""Test that the hooks are working correctly for plugins"""
def test_test_report(self, testdir: Testdir, pytestconfig: Config) -> None:
testdir.makepyfile(
def test_test_report(self, pytester: Pytester, pytestconfig: Config) -> None:
pytester.makepyfile(
"""
def test_a(): assert False
def test_b(): pass
"""
)
reprec = testdir.inline_run()
reprec = pytester.inline_run()
reports = reprec.getreports("pytest_runtest_logreport")
assert len(reports) == 6
for rep in reports:
@ -431,14 +435,14 @@ class TestHooks:
assert new_rep.when == rep.when
assert new_rep.outcome == rep.outcome
def test_collect_report(self, testdir: Testdir, pytestconfig: Config) -> None:
testdir.makepyfile(
def test_collect_report(self, pytester: Pytester, pytestconfig: Config) -> None:
pytester.makepyfile(
"""
def test_a(): assert False
def test_b(): pass
"""
)
reprec = testdir.inline_run()
reprec = pytester.inline_run()
reports = reprec.getreports("pytest_collectreport")
assert len(reports) == 2
for rep in reports:
@ -457,14 +461,14 @@ class TestHooks:
"hook_name", ["pytest_runtest_logreport", "pytest_collectreport"]
)
def test_invalid_report_types(
self, testdir: Testdir, pytestconfig: Config, hook_name: str
self, pytester: Pytester, pytestconfig: Config, hook_name: str
) -> None:
testdir.makepyfile(
pytester.makepyfile(
"""
def test_a(): pass
"""
)
reprec = testdir.inline_run()
reprec = pytester.inline_run()
reports = reprec.getreports(hook_name)
assert reports
rep = reports[0]

View File

@ -2,26 +2,28 @@ import inspect
import os
import sys
import types
from pathlib import Path
from typing import Dict
from typing import List
from typing import Tuple
from typing import Type
import py
import _pytest._code
import pytest
from _pytest import outcomes
from _pytest import reports
from _pytest import runner
from _pytest._code import ExceptionInfo
from _pytest._code.code import ExceptionChainRepr
from _pytest.config import ExitCode
from _pytest.monkeypatch import MonkeyPatch
from _pytest.outcomes import OutcomeException
from _pytest.pytester import Pytester
class TestSetupState:
def test_setup(self, testdir) -> None:
def test_setup(self, pytester: Pytester) -> None:
ss = runner.SetupState()
item = testdir.getitem("def test_func(): pass")
item = pytester.getitem("def test_func(): pass")
values = [1]
ss.prepare(item)
ss.addfinalizer(values.pop, colitem=item)
@ -29,15 +31,15 @@ class TestSetupState:
ss._pop_and_teardown()
assert not values
def test_teardown_exact_stack_empty(self, testdir) -> None:
item = testdir.getitem("def test_func(): pass")
def test_teardown_exact_stack_empty(self, pytester: Pytester) -> None:
item = pytester.getitem("def test_func(): pass")
ss = runner.SetupState()
ss.teardown_exact(item, None)
ss.teardown_exact(item, None)
ss.teardown_exact(item, None)
def test_setup_fails_and_failure_is_cached(self, testdir) -> None:
item = testdir.getitem(
def test_setup_fails_and_failure_is_cached(self, pytester: Pytester) -> None:
item = pytester.getitem(
"""
def setup_module(mod):
raise ValueError(42)
@ -48,7 +50,7 @@ class TestSetupState:
pytest.raises(ValueError, lambda: ss.prepare(item))
pytest.raises(ValueError, lambda: ss.prepare(item))
def test_teardown_multiple_one_fails(self, testdir) -> None:
def test_teardown_multiple_one_fails(self, pytester: Pytester) -> None:
r = []
def fin1():
@ -60,7 +62,7 @@ class TestSetupState:
def fin3():
r.append("fin3")
item = testdir.getitem("def test_func(): pass")
item = pytester.getitem("def test_func(): pass")
ss = runner.SetupState()
ss.addfinalizer(fin1, item)
ss.addfinalizer(fin2, item)
@ -70,7 +72,7 @@ class TestSetupState:
assert err.value.args == ("oops",)
assert r == ["fin3", "fin1"]
def test_teardown_multiple_fail(self, testdir) -> None:
def test_teardown_multiple_fail(self, pytester: Pytester) -> None:
# Ensure the first exception is the one which is re-raised.
# Ideally both would be reported however.
def fin1():
@ -79,7 +81,7 @@ class TestSetupState:
def fin2():
raise Exception("oops2")
item = testdir.getitem("def test_func(): pass")
item = pytester.getitem("def test_func(): pass")
ss = runner.SetupState()
ss.addfinalizer(fin1, item)
ss.addfinalizer(fin2, item)
@ -87,7 +89,7 @@ class TestSetupState:
ss._callfinalizers(item)
assert err.value.args == ("oops2",)
def test_teardown_multiple_scopes_one_fails(self, testdir) -> None:
def test_teardown_multiple_scopes_one_fails(self, pytester: Pytester) -> None:
module_teardown = []
def fin_func():
@ -96,7 +98,7 @@ class TestSetupState:
def fin_module():
module_teardown.append("fin_module")
item = testdir.getitem("def test_func(): pass")
item = pytester.getitem("def test_func(): pass")
ss = runner.SetupState()
ss.addfinalizer(fin_module, item.listchain()[-2])
ss.addfinalizer(fin_func, item)
@ -107,8 +109,8 @@ class TestSetupState:
class BaseFunctionalTests:
def test_passfunction(self, testdir) -> None:
reports = testdir.runitem(
def test_passfunction(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
def test_func():
pass
@ -120,8 +122,8 @@ class BaseFunctionalTests:
assert rep.outcome == "passed"
assert not rep.longrepr
def test_failfunction(self, testdir) -> None:
reports = testdir.runitem(
def test_failfunction(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
def test_func():
assert 0
@ -135,8 +137,8 @@ class BaseFunctionalTests:
assert rep.outcome == "failed"
# assert isinstance(rep.longrepr, ReprExceptionInfo)
def test_skipfunction(self, testdir) -> None:
reports = testdir.runitem(
def test_skipfunction(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
import pytest
def test_func():
@ -155,8 +157,8 @@ class BaseFunctionalTests:
# assert rep.skipped.location.path
# assert not rep.skipped.failurerepr
def test_skip_in_setup_function(self, testdir) -> None:
reports = testdir.runitem(
def test_skip_in_setup_function(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
import pytest
def setup_function(func):
@ -176,8 +178,8 @@ class BaseFunctionalTests:
assert len(reports) == 2
assert reports[1].passed # teardown
def test_failure_in_setup_function(self, testdir) -> None:
reports = testdir.runitem(
def test_failure_in_setup_function(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
import pytest
def setup_function(func):
@ -193,8 +195,8 @@ class BaseFunctionalTests:
assert rep.when == "setup"
assert len(reports) == 2
def test_failure_in_teardown_function(self, testdir) -> None:
reports = testdir.runitem(
def test_failure_in_teardown_function(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
import pytest
def teardown_function(func):
@ -213,8 +215,8 @@ class BaseFunctionalTests:
# assert rep.longrepr.reprcrash.lineno == 3
# assert rep.longrepr.reprtraceback.reprentries
def test_custom_failure_repr(self, testdir) -> None:
testdir.makepyfile(
def test_custom_failure_repr(self, pytester: Pytester) -> None:
pytester.makepyfile(
conftest="""
import pytest
class Function(pytest.Function):
@ -222,7 +224,7 @@ class BaseFunctionalTests:
return "hello"
"""
)
reports = testdir.runitem(
reports = pytester.runitem(
"""
import pytest
def test_func():
@ -238,8 +240,8 @@ class BaseFunctionalTests:
# assert rep.failed.where.path.basename == "test_func.py"
# assert rep.failed.failurerepr == "hello"
def test_teardown_final_returncode(self, testdir) -> None:
rec = testdir.inline_runsource(
def test_teardown_final_returncode(self, pytester: Pytester) -> None:
rec = pytester.inline_runsource(
"""
def test_func():
pass
@ -249,8 +251,8 @@ class BaseFunctionalTests:
)
assert rec.ret == 1
def test_logstart_logfinish_hooks(self, testdir) -> None:
rec = testdir.inline_runsource(
def test_logstart_logfinish_hooks(self, pytester: Pytester) -> None:
rec = pytester.inline_runsource(
"""
import pytest
def test_func():
@ -266,8 +268,8 @@ class BaseFunctionalTests:
assert rep.nodeid == "test_logstart_logfinish_hooks.py::test_func"
assert rep.location == ("test_logstart_logfinish_hooks.py", 1, "test_func")
def test_exact_teardown_issue90(self, testdir) -> None:
rec = testdir.inline_runsource(
def test_exact_teardown_issue90(self, pytester: Pytester) -> None:
rec = pytester.inline_runsource(
"""
import pytest
@ -306,9 +308,9 @@ class BaseFunctionalTests:
assert reps[5].nodeid.endswith("test_func")
assert reps[5].failed
def test_exact_teardown_issue1206(self, testdir) -> None:
def test_exact_teardown_issue1206(self, pytester: Pytester) -> None:
"""Issue shadowing error with wrong number of arguments on teardown_method."""
rec = testdir.inline_runsource(
rec = pytester.inline_runsource(
"""
import pytest
@ -335,14 +337,19 @@ class BaseFunctionalTests:
assert reps[2].nodeid.endswith("test_method")
assert reps[2].failed
assert reps[2].when == "teardown"
assert reps[2].longrepr.reprcrash.message in (
longrepr = reps[2].longrepr
assert isinstance(longrepr, ExceptionChainRepr)
assert longrepr.reprcrash
assert longrepr.reprcrash.message in (
"TypeError: teardown_method() missing 2 required positional arguments: 'y' and 'z'",
# Python >= 3.10
"TypeError: TestClass.teardown_method() missing 2 required positional arguments: 'y' and 'z'",
)
def test_failure_in_setup_function_ignores_custom_repr(self, testdir) -> None:
testdir.makepyfile(
def test_failure_in_setup_function_ignores_custom_repr(
self, pytester: Pytester
) -> None:
pytester.makepyfile(
conftest="""
import pytest
class Function(pytest.Function):
@ -350,7 +357,7 @@ class BaseFunctionalTests:
assert 0
"""
)
reports = testdir.runitem(
reports = pytester.runitem(
"""
def setup_function(func):
raise ValueError(42)
@ -369,9 +376,9 @@ class BaseFunctionalTests:
# assert rep.outcome.where.path.basename == "test_func.py"
# assert instanace(rep.failed.failurerepr, PythonFailureRepr)
def test_systemexit_does_not_bail_out(self, testdir) -> None:
def test_systemexit_does_not_bail_out(self, pytester: Pytester) -> None:
try:
reports = testdir.runitem(
reports = pytester.runitem(
"""
def test_func():
raise SystemExit(42)
@ -383,9 +390,9 @@ class BaseFunctionalTests:
assert rep.failed
assert rep.when == "call"
def test_exit_propagates(self, testdir) -> None:
def test_exit_propagates(self, pytester: Pytester) -> None:
try:
testdir.runitem(
pytester.runitem(
"""
import pytest
def test_func():
@ -405,9 +412,9 @@ class TestExecutionNonForked(BaseFunctionalTests):
return f
def test_keyboardinterrupt_propagates(self, testdir) -> None:
def test_keyboardinterrupt_propagates(self, pytester: Pytester) -> None:
try:
testdir.runitem(
pytester.runitem(
"""
def test_func():
raise KeyboardInterrupt("fake")
@ -420,8 +427,8 @@ class TestExecutionNonForked(BaseFunctionalTests):
class TestSessionReports:
def test_collect_result(self, testdir) -> None:
col = testdir.getmodulecol(
def test_collect_result(self, pytester: Pytester) -> None:
col = pytester.getmodulecol(
"""
def test_func1():
pass
@ -489,8 +496,8 @@ def test_callinfo() -> None:
@pytest.mark.xfail
def test_runtest_in_module_ordering(testdir) -> None:
p1 = testdir.makepyfile(
def test_runtest_in_module_ordering(pytester: Pytester) -> None:
p1 = pytester.makepyfile(
"""
import pytest
def pytest_runtest_setup(item): # runs after class-level!
@ -517,7 +524,7 @@ def test_runtest_in_module_ordering(testdir) -> None:
del item.function.mylist
"""
)
result = testdir.runpytest(p1)
result = pytester.runpytest(p1)
result.stdout.fnmatch_lines(["*2 passed*"])
@ -547,8 +554,8 @@ def test_pytest_fail() -> None:
assert s.startswith("Failed")
def test_pytest_exit_msg(testdir) -> None:
testdir.makeconftest(
def test_pytest_exit_msg(pytester: Pytester) -> None:
pytester.makeconftest(
"""
import pytest
@ -556,7 +563,7 @@ def test_pytest_exit_msg(testdir) -> None:
pytest.exit('oh noes')
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stderr.fnmatch_lines(["Exit: oh noes"])
@ -570,22 +577,22 @@ def _strip_resource_warnings(lines):
]
def test_pytest_exit_returncode(testdir) -> None:
testdir.makepyfile(
def test_pytest_exit_returncode(pytester: Pytester) -> None:
pytester.makepyfile(
"""\
import pytest
def test_foo():
pytest.exit("some exit msg", 99)
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*! *Exit: some exit msg !*"])
assert _strip_resource_warnings(result.stderr.lines) == []
assert result.ret == 99
# It prints to stderr also in case of exit during pytest_sessionstart.
testdir.makeconftest(
pytester.makeconftest(
"""\
import pytest
@ -593,7 +600,7 @@ def test_pytest_exit_returncode(testdir) -> None:
pytest.exit("during_sessionstart", 98)
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*! *Exit: during_sessionstart !*"])
assert _strip_resource_warnings(result.stderr.lines) == [
"Exit: during_sessionstart"
@ -601,9 +608,9 @@ def test_pytest_exit_returncode(testdir) -> None:
assert result.ret == 98
def test_pytest_fail_notrace_runtest(testdir) -> None:
def test_pytest_fail_notrace_runtest(pytester: Pytester) -> None:
"""Test pytest.fail(..., pytrace=False) does not show tracebacks during test run."""
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
def test_hello():
@ -612,14 +619,14 @@ def test_pytest_fail_notrace_runtest(testdir) -> None:
pytest.fail("world", pytrace=False)
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["world", "hello"])
result.stdout.no_fnmatch_line("*def teardown_function*")
def test_pytest_fail_notrace_collection(testdir) -> None:
def test_pytest_fail_notrace_collection(pytester: Pytester) -> None:
"""Test pytest.fail(..., pytrace=False) does not show tracebacks during collection."""
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
def some_internal_function():
@ -627,17 +634,17 @@ def test_pytest_fail_notrace_collection(testdir) -> None:
some_internal_function()
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["hello"])
result.stdout.no_fnmatch_line("*def some_internal_function()*")
def test_pytest_fail_notrace_non_ascii(testdir) -> None:
def test_pytest_fail_notrace_non_ascii(pytester: Pytester) -> None:
"""Fix pytest.fail with pytrace=False with non-ascii characters (#1178).
This tests with native and unicode strings containing non-ascii chars.
"""
testdir.makepyfile(
pytester.makepyfile(
"""\
import pytest
@ -645,28 +652,28 @@ def test_pytest_fail_notrace_non_ascii(testdir) -> None:
pytest.fail('oh oh: ☺', pytrace=False)
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*test_hello*", "oh oh: ☺"])
result.stdout.no_fnmatch_line("*def test_hello*")
def test_pytest_no_tests_collected_exit_status(testdir) -> None:
result = testdir.runpytest()
def test_pytest_no_tests_collected_exit_status(pytester: Pytester) -> None:
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*collected 0 items*"])
assert result.ret == ExitCode.NO_TESTS_COLLECTED
testdir.makepyfile(
pytester.makepyfile(
test_foo="""
def test_foo():
assert 1
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*collected 1 item*"])
result.stdout.fnmatch_lines(["*1 passed*"])
assert result.ret == ExitCode.OK
result = testdir.runpytest("-k nonmatch")
result = pytester.runpytest("-k nonmatch")
result.stdout.fnmatch_lines(["*collected 1 item*"])
result.stdout.fnmatch_lines(["*1 deselected*"])
assert result.ret == ExitCode.NO_TESTS_COLLECTED
@ -677,7 +684,7 @@ def test_exception_printing_skip() -> None:
try:
pytest.skip("hello")
except pytest.skip.Exception:
excinfo = _pytest._code.ExceptionInfo.from_current()
excinfo = ExceptionInfo.from_current()
s = excinfo.exconly(tryshort=True)
assert s.startswith("Skipped")
@ -698,10 +705,10 @@ def test_importorskip(monkeypatch) -> None:
excrepr = excinfo.getrepr()
assert excrepr is not None
assert excrepr.reprcrash is not None
path = py.path.local(excrepr.reprcrash.path)
path = Path(excrepr.reprcrash.path)
# check that importorskip reports the actual call
# in this test the test_runner.py file
assert path.purebasename == "test_runner"
assert path.stem == "test_runner"
pytest.raises(SyntaxError, pytest.importorskip, "x y z")
pytest.raises(SyntaxError, pytest.importorskip, "x=y")
mod = types.ModuleType("hello123")
@ -712,9 +719,7 @@ def test_importorskip(monkeypatch) -> None:
mod2 = pytest.importorskip("hello123", minversion="1.3")
assert mod2 == mod
except pytest.skip.Exception: # pragma: no cover
assert False, "spurious skip: {}".format(
_pytest._code.ExceptionInfo.from_current()
)
assert False, f"spurious skip: {ExceptionInfo.from_current()}"
def test_importorskip_imports_last_module_part() -> None:
@ -732,14 +737,12 @@ def test_importorskip_dev_module(monkeypatch) -> None:
with pytest.raises(pytest.skip.Exception):
pytest.importorskip("mockmodule1", minversion="0.14.0")
except pytest.skip.Exception: # pragma: no cover
assert False, "spurious skip: {}".format(
_pytest._code.ExceptionInfo.from_current()
)
assert False, f"spurious skip: {ExceptionInfo.from_current()}"
def test_importorskip_module_level(testdir) -> None:
def test_importorskip_module_level(pytester: Pytester) -> None:
"""`importorskip` must be able to skip entire modules when used at module level."""
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
foobarbaz = pytest.importorskip("foobarbaz")
@ -748,13 +751,13 @@ def test_importorskip_module_level(testdir) -> None:
pass
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.fnmatch_lines(["*collected 0 items / 1 skipped*"])
def test_importorskip_custom_reason(testdir) -> None:
def test_importorskip_custom_reason(pytester: Pytester) -> None:
"""Make sure custom reasons are used."""
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
foobarbaz = pytest.importorskip("foobarbaz2", reason="just because")
@ -763,13 +766,13 @@ def test_importorskip_custom_reason(testdir) -> None:
pass
"""
)
result = testdir.runpytest("-ra")
result = pytester.runpytest("-ra")
result.stdout.fnmatch_lines(["*just because*"])
result.stdout.fnmatch_lines(["*collected 0 items / 1 skipped*"])
def test_pytest_cmdline_main(testdir) -> None:
p = testdir.makepyfile(
def test_pytest_cmdline_main(pytester: Pytester) -> None:
p = pytester.makepyfile(
"""
import pytest
def test_hello():
@ -786,8 +789,8 @@ def test_pytest_cmdline_main(testdir) -> None:
assert ret == 0
def test_unicode_in_longrepr(testdir) -> None:
testdir.makeconftest(
def test_unicode_in_longrepr(pytester: Pytester) -> None:
pytester.makeconftest(
"""\
import pytest
@pytest.hookimpl(hookwrapper=True)
@ -798,19 +801,19 @@ def test_unicode_in_longrepr(testdir) -> None:
rep.longrepr = 'ä'
"""
)
testdir.makepyfile(
pytester.makepyfile(
"""
def test_out():
assert 0
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
assert result.ret == 1
assert "UnicodeEncodeError" not in result.stderr.str()
def test_failure_in_setup(testdir) -> None:
testdir.makepyfile(
def test_failure_in_setup(pytester: Pytester) -> None:
pytester.makepyfile(
"""
def setup_module():
0/0
@ -818,24 +821,26 @@ def test_failure_in_setup(testdir) -> None:
pass
"""
)
result = testdir.runpytest("--tb=line")
result = pytester.runpytest("--tb=line")
result.stdout.no_fnmatch_line("*def setup_module*")
def test_makereport_getsource(testdir) -> None:
testdir.makepyfile(
def test_makereport_getsource(pytester: Pytester) -> None:
pytester.makepyfile(
"""
def test_foo():
if False: pass
else: assert False
"""
)
result = testdir.runpytest()
result = pytester.runpytest()
result.stdout.no_fnmatch_line("*INTERNALERROR*")
result.stdout.fnmatch_lines(["*else: assert False*"])
def test_makereport_getsource_dynamic_code(testdir, monkeypatch) -> None:
def test_makereport_getsource_dynamic_code(
pytester: Pytester, monkeypatch: MonkeyPatch
) -> None:
"""Test that exception in dynamically generated code doesn't break getting the source line."""
import inspect
@ -849,7 +854,7 @@ def test_makereport_getsource_dynamic_code(testdir, monkeypatch) -> None:
monkeypatch.setattr(inspect, "findsource", findsource)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
@ -861,7 +866,7 @@ def test_makereport_getsource_dynamic_code(testdir, monkeypatch) -> None:
assert False
"""
)
result = testdir.runpytest("-vv")
result = pytester.runpytest("-vv")
result.stdout.no_fnmatch_line("*INTERNALERROR*")
result.stdout.fnmatch_lines(["*test_fix*", "*fixture*'missing'*not found*"])
@ -896,12 +901,12 @@ def test_store_except_info_on_error() -> None:
assert not hasattr(sys, "last_traceback")
def test_current_test_env_var(testdir, monkeypatch) -> None:
def test_current_test_env_var(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
pytest_current_test_vars: List[Tuple[str, str]] = []
monkeypatch.setattr(
sys, "pytest_current_test_vars", pytest_current_test_vars, raising=False
)
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
import sys
@ -917,7 +922,7 @@ def test_current_test_env_var(testdir, monkeypatch) -> None:
sys.pytest_current_test_vars.append(('call', os.environ['PYTEST_CURRENT_TEST']))
"""
)
result = testdir.runpytest_inprocess()
result = pytester.runpytest_inprocess()
assert result.ret == 0
test_id = "test_current_test_env_var.py::test"
assert pytest_current_test_vars == [
@ -934,8 +939,8 @@ class TestReportContents:
def getrunner(self):
return lambda item: runner.runtestprotocol(item, log=False)
def test_longreprtext_pass(self, testdir) -> None:
reports = testdir.runitem(
def test_longreprtext_pass(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
def test_func():
pass
@ -944,9 +949,9 @@ class TestReportContents:
rep = reports[1]
assert rep.longreprtext == ""
def test_longreprtext_skip(self, testdir) -> None:
def test_longreprtext_skip(self, pytester: Pytester) -> None:
"""TestReport.longreprtext can handle non-str ``longrepr`` attributes (#7559)"""
reports = testdir.runitem(
reports = pytester.runitem(
"""
import pytest
def test_func():
@ -957,22 +962,22 @@ class TestReportContents:
assert isinstance(call_rep.longrepr, tuple)
assert "Skipped" in call_rep.longreprtext
def test_longreprtext_collect_skip(self, testdir) -> None:
def test_longreprtext_collect_skip(self, pytester: Pytester) -> None:
"""CollectReport.longreprtext can handle non-str ``longrepr`` attributes (#7559)"""
testdir.makepyfile(
pytester.makepyfile(
"""
import pytest
pytest.skip(allow_module_level=True)
"""
)
rec = testdir.inline_run()
rec = pytester.inline_run()
calls = rec.getcalls("pytest_collectreport")
_, call = calls
assert isinstance(call.report.longrepr, tuple)
assert "Skipped" in call.report.longreprtext
def test_longreprtext_failure(self, testdir) -> None:
reports = testdir.runitem(
def test_longreprtext_failure(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
def test_func():
x = 1
@ -982,8 +987,8 @@ class TestReportContents:
rep = reports[1]
assert "assert 1 == 4" in rep.longreprtext
def test_captured_text(self, testdir) -> None:
reports = testdir.runitem(
def test_captured_text(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
import pytest
import sys
@ -1012,8 +1017,8 @@ class TestReportContents:
assert call.capstderr == "setup: stderr\ncall: stderr\n"
assert teardown.capstderr == "setup: stderr\ncall: stderr\nteardown: stderr\n"
def test_no_captured_text(self, testdir) -> None:
reports = testdir.runitem(
def test_no_captured_text(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
def test_func():
pass
@ -1023,8 +1028,8 @@ class TestReportContents:
assert rep.capstdout == ""
assert rep.capstderr == ""
def test_longrepr_type(self, testdir) -> None:
reports = testdir.runitem(
def test_longrepr_type(self, pytester: Pytester) -> None:
reports = pytester.runitem(
"""
import pytest
def test_func():
@ -1032,7 +1037,7 @@ class TestReportContents:
"""
)
rep = reports[1]
assert isinstance(rep.longrepr, _pytest._code.code.ExceptionRepr)
assert isinstance(rep.longrepr, ExceptionChainRepr)
def test_outcome_exception_bad_msg() -> None: