| # -*- coding: utf-8 -*- |
| from __future__ import absolute_import, division, print_function |
| |
| import _pytest._code |
| import inspect |
| import os |
| import py |
| import pytest |
| import sys |
| import types |
| from _pytest import runner, main, outcomes |
| |
| |
| class TestSetupState(object): |
| |
| def test_setup(self, testdir): |
| ss = runner.SetupState() |
| item = testdir.getitem("def test_func(): pass") |
| values = [1] |
| ss.prepare(item) |
| ss.addfinalizer(values.pop, colitem=item) |
| assert values |
| ss._pop_and_teardown() |
| assert not values |
| |
| def test_teardown_exact_stack_empty(self, testdir): |
| item = testdir.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): |
| item = testdir.getitem( |
| """ |
| def setup_module(mod): |
| raise ValueError(42) |
| def test_func(): pass |
| """ |
| ) |
| ss = runner.SetupState() |
| pytest.raises(ValueError, lambda: ss.prepare(item)) |
| pytest.raises(ValueError, lambda: ss.prepare(item)) |
| |
| def test_teardown_multiple_one_fails(self, testdir): |
| r = [] |
| |
| def fin1(): |
| r.append("fin1") |
| |
| def fin2(): |
| raise Exception("oops") |
| |
| def fin3(): |
| r.append("fin3") |
| |
| item = testdir.getitem("def test_func(): pass") |
| ss = runner.SetupState() |
| ss.addfinalizer(fin1, item) |
| ss.addfinalizer(fin2, item) |
| ss.addfinalizer(fin3, item) |
| with pytest.raises(Exception) as err: |
| ss._callfinalizers(item) |
| assert err.value.args == ("oops",) |
| assert r == ["fin3", "fin1"] |
| |
| def test_teardown_multiple_fail(self, testdir): |
| # Ensure the first exception is the one which is re-raised. |
| # Ideally both would be reported however. |
| def fin1(): |
| raise Exception("oops1") |
| |
| def fin2(): |
| raise Exception("oops2") |
| |
| item = testdir.getitem("def test_func(): pass") |
| ss = runner.SetupState() |
| ss.addfinalizer(fin1, item) |
| ss.addfinalizer(fin2, item) |
| with pytest.raises(Exception) as err: |
| ss._callfinalizers(item) |
| assert err.value.args == ("oops2",) |
| |
| def test_teardown_multiple_scopes_one_fails(self, testdir): |
| module_teardown = [] |
| |
| def fin_func(): |
| raise Exception("oops1") |
| |
| def fin_module(): |
| module_teardown.append("fin_module") |
| |
| item = testdir.getitem("def test_func(): pass") |
| ss = runner.SetupState() |
| ss.addfinalizer(fin_module, item.listchain()[-2]) |
| ss.addfinalizer(fin_func, item) |
| ss.prepare(item) |
| with pytest.raises(Exception, match="oops1"): |
| ss.teardown_exact(item, None) |
| assert module_teardown |
| |
| |
| class BaseFunctionalTests(object): |
| |
| def test_passfunction(self, testdir): |
| reports = testdir.runitem( |
| """ |
| def test_func(): |
| pass |
| """ |
| ) |
| rep = reports[1] |
| assert rep.passed |
| assert not rep.failed |
| assert rep.outcome == "passed" |
| assert not rep.longrepr |
| |
| def test_failfunction(self, testdir): |
| reports = testdir.runitem( |
| """ |
| def test_func(): |
| assert 0 |
| """ |
| ) |
| rep = reports[1] |
| assert not rep.passed |
| assert not rep.skipped |
| assert rep.failed |
| assert rep.when == "call" |
| assert rep.outcome == "failed" |
| # assert isinstance(rep.longrepr, ReprExceptionInfo) |
| |
| def test_skipfunction(self, testdir): |
| reports = testdir.runitem( |
| """ |
| import pytest |
| def test_func(): |
| pytest.skip("hello") |
| """ |
| ) |
| rep = reports[1] |
| assert not rep.failed |
| assert not rep.passed |
| assert rep.skipped |
| assert rep.outcome == "skipped" |
| # assert rep.skipped.when == "call" |
| # assert rep.skipped.when == "call" |
| # assert rep.skipped == "%sreason == "hello" |
| # assert rep.skipped.location.lineno == 3 |
| # assert rep.skipped.location.path |
| # assert not rep.skipped.failurerepr |
| |
| def test_skip_in_setup_function(self, testdir): |
| reports = testdir.runitem( |
| """ |
| import pytest |
| def setup_function(func): |
| pytest.skip("hello") |
| def test_func(): |
| pass |
| """ |
| ) |
| print(reports) |
| rep = reports[0] |
| assert not rep.failed |
| assert not rep.passed |
| assert rep.skipped |
| # assert rep.skipped.reason == "hello" |
| # assert rep.skipped.location.lineno == 3 |
| # assert rep.skipped.location.lineno == 3 |
| assert len(reports) == 2 |
| assert reports[1].passed # teardown |
| |
| def test_failure_in_setup_function(self, testdir): |
| reports = testdir.runitem( |
| """ |
| import pytest |
| def setup_function(func): |
| raise ValueError(42) |
| def test_func(): |
| pass |
| """ |
| ) |
| rep = reports[0] |
| assert not rep.skipped |
| assert not rep.passed |
| assert rep.failed |
| assert rep.when == "setup" |
| assert len(reports) == 2 |
| |
| def test_failure_in_teardown_function(self, testdir): |
| reports = testdir.runitem( |
| """ |
| import pytest |
| def teardown_function(func): |
| raise ValueError(42) |
| def test_func(): |
| pass |
| """ |
| ) |
| print(reports) |
| assert len(reports) == 3 |
| rep = reports[2] |
| assert not rep.skipped |
| assert not rep.passed |
| assert rep.failed |
| assert rep.when == "teardown" |
| # assert rep.longrepr.reprcrash.lineno == 3 |
| # assert rep.longrepr.reprtraceback.reprentries |
| |
| def test_custom_failure_repr(self, testdir): |
| testdir.makepyfile( |
| conftest=""" |
| import pytest |
| class Function(pytest.Function): |
| def repr_failure(self, excinfo): |
| return "hello" |
| """ |
| ) |
| reports = testdir.runitem( |
| """ |
| import pytest |
| def test_func(): |
| assert 0 |
| """ |
| ) |
| rep = reports[1] |
| assert not rep.skipped |
| assert not rep.passed |
| assert rep.failed |
| # assert rep.outcome.when == "call" |
| # assert rep.failed.where.lineno == 3 |
| # assert rep.failed.where.path.basename == "test_func.py" |
| # assert rep.failed.failurerepr == "hello" |
| |
| def test_teardown_final_returncode(self, testdir): |
| rec = testdir.inline_runsource( |
| """ |
| def test_func(): |
| pass |
| def teardown_function(func): |
| raise ValueError(42) |
| """ |
| ) |
| assert rec.ret == 1 |
| |
| def test_logstart_logfinish_hooks(self, testdir): |
| rec = testdir.inline_runsource( |
| """ |
| import pytest |
| def test_func(): |
| pass |
| """ |
| ) |
| reps = rec.getcalls("pytest_runtest_logstart pytest_runtest_logfinish") |
| assert ( |
| [x._name for x in reps] |
| == ["pytest_runtest_logstart", "pytest_runtest_logfinish"] |
| ) |
| for rep in reps: |
| 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): |
| rec = testdir.inline_runsource( |
| """ |
| import pytest |
| |
| class TestClass(object): |
| def test_method(self): |
| pass |
| def teardown_class(cls): |
| raise Exception() |
| |
| def test_func(): |
| import sys |
| # on python2 exc_info is keept till a function exits |
| # so we would end up calling test functions while |
| # sys.exc_info would return the indexerror |
| # from guessing the lastitem |
| excinfo = sys.exc_info() |
| import traceback |
| assert excinfo[0] is None, \ |
| traceback.format_exception(*excinfo) |
| def teardown_function(func): |
| raise ValueError(42) |
| """ |
| ) |
| reps = rec.getreports("pytest_runtest_logreport") |
| print(reps) |
| for i in range(2): |
| assert reps[i].nodeid.endswith("test_method") |
| assert reps[i].passed |
| assert reps[2].when == "teardown" |
| assert reps[2].failed |
| assert len(reps) == 6 |
| for i in range(3, 5): |
| assert reps[i].nodeid.endswith("test_func") |
| assert reps[i].passed |
| assert reps[5].when == "teardown" |
| assert reps[5].nodeid.endswith("test_func") |
| assert reps[5].failed |
| |
| def test_exact_teardown_issue1206(self, testdir): |
| """issue shadowing error with wrong number of arguments on teardown_method.""" |
| rec = testdir.inline_runsource( |
| """ |
| import pytest |
| |
| class TestClass(object): |
| def teardown_method(self, x, y, z): |
| pass |
| |
| def test_method(self): |
| assert True |
| """ |
| ) |
| reps = rec.getreports("pytest_runtest_logreport") |
| print(reps) |
| assert len(reps) == 3 |
| # |
| assert reps[0].nodeid.endswith("test_method") |
| assert reps[0].passed |
| assert reps[0].when == "setup" |
| # |
| assert reps[1].nodeid.endswith("test_method") |
| assert reps[1].passed |
| assert reps[1].when == "call" |
| # |
| assert reps[2].nodeid.endswith("test_method") |
| assert reps[2].failed |
| assert reps[2].when == "teardown" |
| assert reps[2].longrepr.reprcrash.message in ( |
| # python3 error |
| "TypeError: teardown_method() missing 2 required positional arguments: 'y' and 'z'", |
| # python2 error |
| "TypeError: teardown_method() takes exactly 4 arguments (2 given)", |
| ) |
| |
| def test_failure_in_setup_function_ignores_custom_repr(self, testdir): |
| testdir.makepyfile( |
| conftest=""" |
| import pytest |
| class Function(pytest.Function): |
| def repr_failure(self, excinfo): |
| assert 0 |
| """ |
| ) |
| reports = testdir.runitem( |
| """ |
| def setup_function(func): |
| raise ValueError(42) |
| def test_func(): |
| pass |
| """ |
| ) |
| assert len(reports) == 2 |
| rep = reports[0] |
| print(rep) |
| assert not rep.skipped |
| assert not rep.passed |
| assert rep.failed |
| # assert rep.outcome.when == "setup" |
| # assert rep.outcome.where.lineno == 3 |
| # assert rep.outcome.where.path.basename == "test_func.py" |
| # assert instanace(rep.failed.failurerepr, PythonFailureRepr) |
| |
| def test_systemexit_does_not_bail_out(self, testdir): |
| try: |
| reports = testdir.runitem( |
| """ |
| def test_func(): |
| raise SystemExit(42) |
| """ |
| ) |
| except SystemExit: |
| pytest.fail("runner did not catch SystemExit") |
| rep = reports[1] |
| assert rep.failed |
| assert rep.when == "call" |
| |
| def test_exit_propagates(self, testdir): |
| try: |
| testdir.runitem( |
| """ |
| import pytest |
| def test_func(): |
| raise pytest.exit.Exception() |
| """ |
| ) |
| except pytest.exit.Exception: |
| pass |
| else: |
| pytest.fail("did not raise") |
| |
| |
| class TestExecutionNonForked(BaseFunctionalTests): |
| |
| def getrunner(self): |
| |
| def f(item): |
| return runner.runtestprotocol(item, log=False) |
| |
| return f |
| |
| def test_keyboardinterrupt_propagates(self, testdir): |
| try: |
| testdir.runitem( |
| """ |
| def test_func(): |
| raise KeyboardInterrupt("fake") |
| """ |
| ) |
| except KeyboardInterrupt: |
| pass |
| else: |
| pytest.fail("did not raise") |
| |
| |
| class TestExecutionForked(BaseFunctionalTests): |
| pytestmark = pytest.mark.skipif("not hasattr(os, 'fork')") |
| |
| def getrunner(self): |
| # XXX re-arrange this test to live in pytest-xdist |
| boxed = pytest.importorskip("xdist.boxed") |
| return boxed.forked_run_report |
| |
| def test_suicide(self, testdir): |
| reports = testdir.runitem( |
| """ |
| def test_func(): |
| import os |
| os.kill(os.getpid(), 15) |
| """ |
| ) |
| rep = reports[0] |
| assert rep.failed |
| assert rep.when == "???" |
| |
| |
| class TestSessionReports(object): |
| |
| def test_collect_result(self, testdir): |
| col = testdir.getmodulecol( |
| """ |
| def test_func1(): |
| pass |
| class TestClass(object): |
| pass |
| """ |
| ) |
| rep = runner.collect_one_node(col) |
| assert not rep.failed |
| assert not rep.skipped |
| assert rep.passed |
| locinfo = rep.location |
| assert locinfo[0] == col.fspath.basename |
| assert not locinfo[1] |
| assert locinfo[2] == col.fspath.basename |
| res = rep.result |
| assert len(res) == 2 |
| assert res[0].name == "test_func1" |
| assert res[1].name == "TestClass" |
| |
| |
| reporttypes = [ |
| runner.BaseReport, |
| runner.TestReport, |
| runner.TeardownErrorReport, |
| runner.CollectReport, |
| ] |
| |
| |
| @pytest.mark.parametrize( |
| "reporttype", reporttypes, ids=[x.__name__ for x in reporttypes] |
| ) |
| def test_report_extra_parameters(reporttype): |
| if hasattr(inspect, "signature"): |
| args = list(inspect.signature(reporttype.__init__).parameters.keys())[1:] |
| else: |
| args = inspect.getargspec(reporttype.__init__)[0][1:] |
| basekw = dict.fromkeys(args, []) |
| report = reporttype(newthing=1, **basekw) |
| assert report.newthing == 1 |
| |
| |
| def test_callinfo(): |
| ci = runner.CallInfo(lambda: 0, "123") |
| assert ci.when == "123" |
| assert ci.result == 0 |
| assert "result" in repr(ci) |
| ci = runner.CallInfo(lambda: 0 / 0, "123") |
| assert ci.when == "123" |
| assert not hasattr(ci, "result") |
| assert ci.excinfo |
| assert "exc" in repr(ci) |
| |
| |
| # design question: do we want general hooks in python files? |
| # then something like the following functional tests makes sense |
| |
| |
| @pytest.mark.xfail |
| def test_runtest_in_module_ordering(testdir): |
| p1 = testdir.makepyfile( |
| """ |
| import pytest |
| def pytest_runtest_setup(item): # runs after class-level! |
| item.function.mylist.append("module") |
| class TestClass(object): |
| def pytest_runtest_setup(self, item): |
| assert not hasattr(item.function, 'mylist') |
| item.function.mylist = ['class'] |
| @pytest.fixture |
| def mylist(self, request): |
| return request.function.mylist |
| def pytest_runtest_call(self, item, __multicall__): |
| try: |
| __multicall__.execute() |
| except ValueError: |
| pass |
| def test_hello1(self, mylist): |
| assert mylist == ['class', 'module'], mylist |
| raise ValueError() |
| def test_hello2(self, mylist): |
| assert mylist == ['class', 'module'], mylist |
| def pytest_runtest_teardown(item): |
| del item.function.mylist |
| """ |
| ) |
| result = testdir.runpytest(p1) |
| result.stdout.fnmatch_lines(["*2 passed*"]) |
| |
| |
| def test_outcomeexception_exceptionattributes(): |
| outcome = outcomes.OutcomeException("test") |
| assert outcome.args[0] == outcome.msg |
| |
| |
| def test_outcomeexception_passes_except_Exception(): |
| with pytest.raises(outcomes.OutcomeException): |
| try: |
| raise outcomes.OutcomeException("test") |
| except Exception: |
| pass |
| |
| |
| def test_pytest_exit(): |
| try: |
| pytest.exit("hello") |
| except pytest.exit.Exception: |
| excinfo = _pytest._code.ExceptionInfo() |
| assert excinfo.errisinstance(KeyboardInterrupt) |
| |
| |
| def test_pytest_fail(): |
| try: |
| pytest.fail("hello") |
| except pytest.fail.Exception: |
| excinfo = _pytest._code.ExceptionInfo() |
| s = excinfo.exconly(tryshort=True) |
| assert s.startswith("Failed") |
| |
| |
| def test_pytest_exit_msg(testdir): |
| testdir.makeconftest( |
| """ |
| import pytest |
| |
| def pytest_configure(config): |
| pytest.exit('oh noes') |
| """ |
| ) |
| result = testdir.runpytest() |
| result.stderr.fnmatch_lines(["Exit: oh noes"]) |
| |
| |
| def test_pytest_fail_notrace(testdir): |
| testdir.makepyfile( |
| """ |
| import pytest |
| def test_hello(): |
| pytest.fail("hello", pytrace=False) |
| def teardown_function(function): |
| pytest.fail("world", pytrace=False) |
| """ |
| ) |
| result = testdir.runpytest() |
| result.stdout.fnmatch_lines(["world", "hello"]) |
| assert "def teardown_function" not in result.stdout.str() |
| |
| |
| @pytest.mark.parametrize("str_prefix", ["u", ""]) |
| def test_pytest_fail_notrace_non_ascii(testdir, str_prefix): |
| """Fix pytest.fail with pytrace=False with non-ascii characters (#1178). |
| |
| This tests with native and unicode strings containing non-ascii chars. |
| """ |
| testdir.makepyfile( |
| u""" |
| # coding: utf-8 |
| import pytest |
| |
| def test_hello(): |
| pytest.fail(%s'oh oh: โบ', pytrace=False) |
| """ |
| % str_prefix |
| ) |
| result = testdir.runpytest() |
| if sys.version_info[0] >= 3: |
| result.stdout.fnmatch_lines(["*test_hello*", "oh oh: โบ"]) |
| else: |
| result.stdout.fnmatch_lines(["*test_hello*", "oh oh: *"]) |
| assert "def test_hello" not in result.stdout.str() |
| |
| |
| def test_pytest_no_tests_collected_exit_status(testdir): |
| result = testdir.runpytest() |
| result.stdout.fnmatch_lines("*collected 0 items*") |
| assert result.ret == main.EXIT_NOTESTSCOLLECTED |
| |
| testdir.makepyfile( |
| test_foo=""" |
| def test_foo(): |
| assert 1 |
| """ |
| ) |
| result = testdir.runpytest() |
| result.stdout.fnmatch_lines("*collected 1 item*") |
| result.stdout.fnmatch_lines("*1 passed*") |
| assert result.ret == main.EXIT_OK |
| |
| result = testdir.runpytest("-k nonmatch") |
| result.stdout.fnmatch_lines("*collected 1 item*") |
| result.stdout.fnmatch_lines("*1 deselected*") |
| assert result.ret == main.EXIT_NOTESTSCOLLECTED |
| |
| |
| def test_exception_printing_skip(): |
| try: |
| pytest.skip("hello") |
| except pytest.skip.Exception: |
| excinfo = _pytest._code.ExceptionInfo() |
| s = excinfo.exconly(tryshort=True) |
| assert s.startswith("Skipped") |
| |
| |
| def test_importorskip(monkeypatch): |
| importorskip = pytest.importorskip |
| |
| def f(): |
| importorskip("asdlkj") |
| |
| try: |
| sysmod = importorskip("sys") |
| assert sysmod is sys |
| # path = pytest.importorskip("os.path") |
| # assert path == os.path |
| excinfo = pytest.raises(pytest.skip.Exception, f) |
| path = py.path.local(excinfo.getrepr().reprcrash.path) |
| # check that importorskip reports the actual call |
| # in this test the test_runner.py file |
| assert path.purebasename == "test_runner" |
| pytest.raises(SyntaxError, "pytest.importorskip('x y z')") |
| pytest.raises(SyntaxError, "pytest.importorskip('x=y')") |
| mod = types.ModuleType("hello123") |
| mod.__version__ = "1.3" |
| monkeypatch.setitem(sys.modules, "hello123", mod) |
| pytest.raises( |
| pytest.skip.Exception, |
| """ |
| pytest.importorskip("hello123", minversion="1.3.1") |
| """, |
| ) |
| mod2 = pytest.importorskip("hello123", minversion="1.3") |
| assert mod2 == mod |
| except pytest.skip.Exception: |
| print(_pytest._code.ExceptionInfo()) |
| pytest.fail("spurious skip") |
| |
| |
| def test_importorskip_imports_last_module_part(): |
| ospath = pytest.importorskip("os.path") |
| assert os.path == ospath |
| |
| |
| def test_importorskip_dev_module(monkeypatch): |
| try: |
| mod = types.ModuleType("mockmodule") |
| mod.__version__ = "0.13.0.dev-43290" |
| monkeypatch.setitem(sys.modules, "mockmodule", mod) |
| mod2 = pytest.importorskip("mockmodule", minversion="0.12.0") |
| assert mod2 == mod |
| pytest.raises( |
| pytest.skip.Exception, |
| """ |
| pytest.importorskip('mockmodule1', minversion='0.14.0')""", |
| ) |
| except pytest.skip.Exception: |
| print(_pytest._code.ExceptionInfo()) |
| pytest.fail("spurious skip") |
| |
| |
| def test_importorskip_module_level(testdir): |
| """importorskip must be able to skip entire modules when used at module level""" |
| testdir.makepyfile( |
| """ |
| import pytest |
| foobarbaz = pytest.importorskip("foobarbaz") |
| |
| def test_foo(): |
| pass |
| """ |
| ) |
| result = testdir.runpytest() |
| result.stdout.fnmatch_lines(["*collected 0 items / 1 skipped*"]) |
| |
| |
| def test_pytest_cmdline_main(testdir): |
| p = testdir.makepyfile( |
| """ |
| import pytest |
| def test_hello(): |
| assert 1 |
| if __name__ == '__main__': |
| pytest.cmdline.main([__file__]) |
| """ |
| ) |
| import subprocess |
| |
| popen = subprocess.Popen([sys.executable, str(p)], stdout=subprocess.PIPE) |
| popen.communicate() |
| ret = popen.wait() |
| assert ret == 0 |
| |
| |
| def test_unicode_in_longrepr(testdir): |
| testdir.makeconftest( |
| """ |
| # -*- coding: utf-8 -*- |
| import pytest |
| @pytest.hookimpl(hookwrapper=True) |
| def pytest_runtest_makereport(): |
| outcome = yield |
| rep = outcome.get_result() |
| if rep.when == "call": |
| rep.longrepr = u'รค' |
| """ |
| ) |
| testdir.makepyfile( |
| """ |
| def test_out(): |
| assert 0 |
| """ |
| ) |
| result = testdir.runpytest() |
| assert result.ret == 1 |
| assert "UnicodeEncodeError" not in result.stderr.str() |
| |
| |
| def test_failure_in_setup(testdir): |
| testdir.makepyfile( |
| """ |
| def setup_module(): |
| 0/0 |
| def test_func(): |
| pass |
| """ |
| ) |
| result = testdir.runpytest("--tb=line") |
| assert "def setup_module" not in result.stdout.str() |
| |
| |
| def test_makereport_getsource(testdir): |
| testdir.makepyfile( |
| """ |
| def test_foo(): |
| if False: pass |
| else: assert False |
| """ |
| ) |
| result = testdir.runpytest() |
| assert "INTERNALERROR" not in result.stdout.str() |
| result.stdout.fnmatch_lines(["*else: assert False*"]) |
| |
| |
| def test_makereport_getsource_dynamic_code(testdir, monkeypatch): |
| """Test that exception in dynamically generated code doesn't break getting the source line.""" |
| import inspect |
| |
| original_findsource = inspect.findsource |
| |
| def findsource(obj, *args, **kwargs): |
| # Can be triggered by dynamically created functions |
| if obj.__name__ == "foo": |
| raise IndexError() |
| return original_findsource(obj, *args, **kwargs) |
| |
| monkeypatch.setattr(inspect, "findsource", findsource) |
| |
| testdir.makepyfile( |
| """ |
| import pytest |
| |
| @pytest.fixture |
| def foo(missing): |
| pass |
| |
| def test_fix(foo): |
| assert False |
| """ |
| ) |
| result = testdir.runpytest("-vv") |
| assert "INTERNALERROR" not in result.stdout.str() |
| result.stdout.fnmatch_lines(["*test_fix*", "*fixture*'missing'*not found*"]) |
| |
| |
| def test_store_except_info_on_error(): |
| """ Test that upon test failure, the exception info is stored on |
| sys.last_traceback and friends. |
| """ |
| # Simulate item that might raise a specific exception, depending on `raise_error` class var |
| class ItemMightRaise(object): |
| nodeid = "item_that_raises" |
| raise_error = True |
| |
| def runtest(self): |
| if self.raise_error: |
| raise IndexError("TEST") |
| |
| try: |
| runner.pytest_runtest_call(ItemMightRaise()) |
| except IndexError: |
| pass |
| # Check that exception info is stored on sys |
| assert sys.last_type is IndexError |
| assert sys.last_value.args[0] == "TEST" |
| assert sys.last_traceback |
| |
| # The next run should clear the exception info stored by the previous run |
| ItemMightRaise.raise_error = False |
| runner.pytest_runtest_call(ItemMightRaise()) |
| assert sys.last_type is None |
| assert sys.last_value is None |
| assert sys.last_traceback is None |
| |
| |
| def test_current_test_env_var(testdir, monkeypatch): |
| pytest_current_test_vars = [] |
| monkeypatch.setattr( |
| sys, "pytest_current_test_vars", pytest_current_test_vars, raising=False |
| ) |
| testdir.makepyfile( |
| """ |
| import pytest |
| import sys |
| import os |
| |
| @pytest.fixture |
| def fix(): |
| sys.pytest_current_test_vars.append(('setup', os.environ['PYTEST_CURRENT_TEST'])) |
| yield |
| sys.pytest_current_test_vars.append(('teardown', os.environ['PYTEST_CURRENT_TEST'])) |
| |
| def test(fix): |
| sys.pytest_current_test_vars.append(('call', os.environ['PYTEST_CURRENT_TEST'])) |
| """ |
| ) |
| result = testdir.runpytest_inprocess() |
| assert result.ret == 0 |
| test_id = "test_current_test_env_var.py::test" |
| assert ( |
| pytest_current_test_vars |
| == [ |
| ("setup", test_id + " (setup)"), |
| ("call", test_id + " (call)"), |
| ("teardown", test_id + " (teardown)"), |
| ] |
| ) |
| assert "PYTEST_CURRENT_TEST" not in os.environ |
| |
| |
| class TestReportContents(object): |
| """ |
| Test user-level API of ``TestReport`` objects. |
| """ |
| |
| def getrunner(self): |
| return lambda item: runner.runtestprotocol(item, log=False) |
| |
| def test_longreprtext_pass(self, testdir): |
| reports = testdir.runitem( |
| """ |
| def test_func(): |
| pass |
| """ |
| ) |
| rep = reports[1] |
| assert rep.longreprtext == "" |
| |
| def test_longreprtext_failure(self, testdir): |
| reports = testdir.runitem( |
| """ |
| def test_func(): |
| x = 1 |
| assert x == 4 |
| """ |
| ) |
| rep = reports[1] |
| assert "assert 1 == 4" in rep.longreprtext |
| |
| def test_captured_text(self, testdir): |
| reports = testdir.runitem( |
| """ |
| import pytest |
| import sys |
| |
| @pytest.fixture |
| def fix(): |
| sys.stdout.write('setup: stdout\\n') |
| sys.stderr.write('setup: stderr\\n') |
| yield |
| sys.stdout.write('teardown: stdout\\n') |
| sys.stderr.write('teardown: stderr\\n') |
| assert 0 |
| |
| def test_func(fix): |
| sys.stdout.write('call: stdout\\n') |
| sys.stderr.write('call: stderr\\n') |
| assert 0 |
| """ |
| ) |
| setup, call, teardown = reports |
| assert setup.capstdout == "setup: stdout\n" |
| assert call.capstdout == "setup: stdout\ncall: stdout\n" |
| assert teardown.capstdout == "setup: stdout\ncall: stdout\nteardown: stdout\n" |
| |
| assert setup.capstderr == "setup: stderr\n" |
| 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): |
| reports = testdir.runitem( |
| """ |
| def test_func(): |
| pass |
| """ |
| ) |
| rep = reports[1] |
| assert rep.capstdout == "" |
| assert rep.capstderr == "" |