def test_hookvalidation_optional(pytester: Pytester) -> None: pytester.makeconftest( """ import pytest @pytest.hookimpl(optionalhook=True) def pytest_hello(xyz): pass """ ) result = pytester.runpytest() assert result.ret == ExitCode.NO_TESTS_COLLECTED
def test_deprecation_of_cmdline_preparse(pytester: Pytester) -> None: pytester.makeconftest(""" def pytest_cmdline_preparse(config, args): ... """) result = pytester.runpytest() result.stdout.fnmatch_lines([ "*PytestRemovedIn8Warning: The pytest_cmdline_preparse hook is deprecated*", "*Please use pytest_load_initial_conftests hook instead.*", ])
def test_initialization_error_issue49(self, pytester: Pytester) -> None: pytester.makeconftest( """ def pytest_configure(): x """ ) result = pytester.runpytest() assert result.ret == 3 # internal error result.stderr.fnmatch_lines(["INTERNAL*pytest_configure*", "INTERNAL*x*"]) assert "sessionstarttime" not in result.stderr.str()
def test_early_hook_configure_error_issue38(self, pytester: Pytester) -> None: pytester.makeconftest(""" def pytest_configure(): 0 / 0 """) result = pytester.runpytest(pytester.path) assert result.ret != 0 # here we get it on stderr result.stderr.fnmatch_lines( ["*INTERNALERROR*File*conftest.py*line 2*", "*0 / 0*"])
def test_issue93_initialnode_importing_capturing( self, pytester: Pytester) -> None: pytester.makeconftest(""" import sys print("should not be seen") sys.stderr.write("stder42\\n") """) result = pytester.runpytest() assert result.ret == ExitCode.NO_TESTS_COLLECTED result.stdout.no_fnmatch_line("*should not be seen*") assert "stderr42" not in result.stderr.str()
def test_addhooks_nohooks(self, pytester: Pytester) -> None: pytester.makeconftest( """ import sys def pytest_addhooks(pluginmanager): pluginmanager.add_hookspecs(sys) """ ) res = pytester.runpytest() assert res.ret != 0 res.stderr.fnmatch_lines(["*did not find*sys*"])
def test_directory_skipped(self, pytester: Pytester) -> None: pytester.makeconftest( """ import pytest def pytest_ignore_collect(): pytest.skip("intentional") """ ) pytester.makepyfile("def test_hello(): pass") result = pytester.runpytest() assert result.ret == ExitCode.NO_TESTS_COLLECTED result.stdout.fnmatch_lines(["*1 skipped*"])
def test_tag_stages(request, pytester: Pytester, docker_client: DockerClient): builder_tag = "localhost/pytest-docker-tools/buildtest:builder" latest_tag = "localhost/pytest-docker-tools/buildtest:latest" def _cleanup(): for tag in (builder_tag, latest_tag): try: docker_client.images.remove(tag) except ImageNotFound: return request.addfinalizer(_cleanup) with pytest.raises(ImageNotFound): for tag in (builder_tag, latest_tag): docker_client.images.get(tag) # A fake multi stage build. pytester.makefile( "", Dockerfile="\n".join(( "FROM alpine:3.13 AS builder", "RUN touch /hello-intermediate-step", "RUN touch /hello", "FROM alpine:3.13", "COPY --from=builder /hello /hello", )), ) pytester.makeconftest("\n".join(( "from pytest_docker_tools import build", "myimage = build(", " path='.',", f" tag='{latest_tag}',", f" stages={{'builder': '{builder_tag}'}},", ")", ))) pytester.makepyfile(test_reusable_network="\n".join(( "def test_session_1(myimage):", f" assert '{latest_tag}' in myimage.tags", ))) result = pytester.runpytest() result.assert_outcomes(passed=1) latest = docker_client.images.get(latest_tag) assert latest is not None builder = docker_client.images.get(builder_tag) assert builder is not None assert latest.id != builder.id
def test_reusable_reused(request, pytester: Pytester, docker_client: DockerClient): def _cleanup(): try: container = docker_client.containers.get("test_reusable_reused") except NotFound: return container.remove(force=True) with pytest.raises(NotFound): docker_client.containers.get("test_reusable_reused") request.addfinalizer(_cleanup) pytester.makeconftest( "\n".join( ( "from pytest_docker_tools import container, fetch", "memcache_image = fetch(repository='memcached:latest')", "memcache = container(", " name='test_reusable_reused',", " image='{memcache_image.id}',", " scope='session',", " ports={", " '11211/tcp': None,", " },", ")", ) ) ) pytester.makepyfile( test_reusable_container="\n".join( ( "import socket", "def test_session_1(memcache):", " sock = socket.socket()", " sock.connect(('127.0.0.1', memcache.ports['11211/tcp'][0]))", " sock.close()", ) ) ) result = pytester.runpytest("--reuse-containers") result.assert_outcomes(passed=1) run1 = docker_client.containers.get("test_reusable_reused") result = pytester.runpytest("--reuse-containers") result.assert_outcomes(passed=1) run2 = docker_client.containers.get("test_reusable_reused") assert run1.id == run2.id
def test_reusable_stale(request, pytester: Pytester, docker_client: DockerClient): def _cleanup(): try: volume = docker_client.volumes.get("test_reusable_stale") except NotFound: return volume.remove() with pytest.raises(NotFound): docker_client.volumes.get("test_reusable_stale") request.addfinalizer(_cleanup) pytester.makeconftest("\n".join(( "from pytest_docker_tools import volume", "memcache_volume = volume(", " name='test_reusable_stale',", ")", ))) pytester.makepyfile(test_reusable_volume="\n".join(( "def test_session_1(memcache_volume):", " assert memcache_volume.name == 'test_reusable_stale'", ))) result = pytester.runpytest("--reuse-containers") result.assert_outcomes(passed=1) run1 = docker_client.volumes.get("test_reusable_stale") # Running again immediately shouldn't recreate the volume result = pytester.runpytest("--reuse-containers") result.assert_outcomes(passed=1) # This would explode if the volume had been removed run1.reload() # Add a label to the volume to make it stale pytester.makeconftest("\n".join(( "from pytest_docker_tools import volume", "memcache_volume = volume(", " name='test_reusable_stale',", " labels={'my-label': 'testtesttest'},", ")", ))) result = pytester.runpytest("--reuse-containers") result.assert_outcomes(passed=1) # It should be replaced by a volume with labels on it run2 = docker_client.volumes.get("test_reusable_stale") run2.attrs["Labels"]["my-label"] == "testtesttest"
def test_none_help_param_raises_exception(pytester: Pytester) -> None: """Test that a None help param raises a TypeError.""" pytester.makeconftest( """ def pytest_addoption(parser): parser.addini("test_ini", None, default=True, type="bool") """ ) result = pytester.runpytest("--help") result.stderr.fnmatch_lines( ["*TypeError: help argument cannot be None for test_ini*"] )
def test_conftest_warning_captured(self, pytester: Pytester) -> None: """Warnings raised during importing of conftest.py files is captured (#2891).""" pytester.makeconftest( """ import warnings warnings.warn(UserWarning("my custom warning")) """ ) result = pytester.runpytest() result.stdout.fnmatch_lines( ["conftest.py:2", "*UserWarning: my custom warning*"] )
def test_pytest_pycollect_makeitem(self, pytester: Pytester) -> None: pytester.makeconftest(""" import pytest class MyFunction(pytest.Function): pass def pytest_pycollect_makeitem(collector, name, obj): if name == "some": return MyFunction.from_parent(name=name, parent=collector) """) pytester.makepyfile("def some(): pass") result = pytester.runpytest("--collect-only") result.stdout.fnmatch_lines(["*MyFunction*some*"])
def test_early_skip(self, pytester: Pytester) -> None: pytester.mkdir("xyz") pytester.makeconftest( """ import pytest def pytest_collect_file(): pytest.skip("early") """ ) result = pytester.runpytest() assert result.ret == ExitCode.NO_TESTS_COLLECTED result.stdout.fnmatch_lines(["*1 skip*"])
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" pytester.makeconftest(""" import pytest import logging def pytest_runtest_protocol(item, nextitem): logging.warning('Unknown Section!') def pytest_runtest_logstart(): logging.warning('>>>>> START >>>>>') def pytest_runtest_logfinish(): logging.warning('<<<<< END <<<<<<<') """) pytester.makepyfile(""" import pytest import logging @pytest.fixture def fix(request): logging.warning("log message from setup of {}".format(request.node.name)) yield logging.warning("log message from teardown of {}".format(request.node.name)) def test_log_1(fix): logging.warning("log message from test_log_1") """) pytester.makeini(""" [pytest] log_cli=true """) result = pytester.runpytest() result.stdout.fnmatch_lines([ "*WARNING*Unknown Section*", f"{filename}::test_log_1 ", "*WARNING* >>>>> START >>>>>*", "*-- live log setup --*", "*WARNING*log message from setup of test_log_1*", "*-- live log call --*", "*WARNING*log message from test_log_1*", "PASSED *100%*", "*-- live log teardown --*", "*WARNING*log message from teardown of test_log_1*", "*WARNING* <<<<< END <<<<<<<*", "=* 1 passed in *=", ])
def test_config_cache(self, pytester: Pytester) -> None: pytester.makeconftest(""" def pytest_configure(config): # see that we get cache information early on assert hasattr(config, "cache") """) pytester.makepyfile(""" def test_session(pytestconfig): assert hasattr(pytestconfig, "cache") """) result = pytester.runpytest() assert result.ret == 0 result.stdout.fnmatch_lines(["*1 passed*"])
def test_file_not_found_unconfigure_issue143(self, pytester: Pytester) -> None: pytester.makeconftest( """ def pytest_configure(): print("---configure") def pytest_unconfigure(): print("---unconfigure") """ ) result = pytester.runpytest("-s", "asd") assert result.ret == ExitCode.USAGE_ERROR result.stderr.fnmatch_lines(["ERROR: file or directory not found: asd"]) result.stdout.fnmatch_lines(["*---configure", "*---unconfigure"])
def test_itemreport_reportinfo(self, pytester: Pytester) -> None: pytester.makeconftest(""" import pytest class MyFunction(pytest.Function): def reportinfo(self): return "ABCDE", 42, "custom" def pytest_pycollect_makeitem(collector, name, obj): if name == "test_func": return MyFunction.from_parent(name=name, parent=collector) """) item = pytester.getitem("def test_func(): pass") item.config.pluginmanager.getplugin("runner") assert item.location == ("ABCDE", 42, "custom")
def test_set_own_labels(request, pytester: Pytester, docker_client: DockerClient): def _cleanup(): try: container = docker_client.containers.get("test_set_own_labels") except NotFound: return container.remove(force=True) with pytest.raises(NotFound): docker_client.containers.get("test_set_own_labels") request.addfinalizer(_cleanup) pytester.makeconftest( "\n".join( ( "from pytest_docker_tools import container, fetch", "memcache_image = fetch(repository='memcached:latest')", "memcache = container(", " name='test_set_own_labels',", " image='{memcache_image.id}',", " scope='session',", " labels={'my-label': 'testtesttest'},", " ports={", " '11211/tcp': None,", " },", ")", ) ) ) pytester.makepyfile( test_reusable_container="\n".join( ( "import socket", "def test_session_1(memcache):", " sock = socket.socket()", " sock.connect(('127.0.0.1', memcache.ports['11211/tcp'][0]))", " sock.close()", ) ) ) result = pytester.runpytest("--reuse-containers") result.assert_outcomes(passed=1) container = docker_client.containers.get("test_set_own_labels") labels = container.attrs["Config"]["Labels"] assert labels["creator"] == "pytest-docker-tools" assert labels["pytest-docker-tools.reusable"] == "True" assert labels["my-label"] == "testtesttest"
def test_module_scoped_task_group_fixture(testdir: Pytester) -> None: testdir.makeconftest(""" import pytest from anyio import ( CancelScope, create_memory_object_stream, create_task_group, get_all_backends, ) @pytest.fixture(scope="module", params=get_all_backends()) def anyio_backend(): return 'asyncio' @pytest.fixture(scope="module") async def task_group(): async with create_task_group() as tg: yield tg @pytest.fixture async def streams(task_group): async def echo_messages(*, task_status): with CancelScope() as cancel_scope: task_status.started(cancel_scope) async for obj in receive1: await send2.send(obj) send1, receive1 = create_memory_object_stream() send2, receive2 = create_memory_object_stream() cancel_scope = await task_group.start(echo_messages) yield send1, receive2 cancel_scope.cancel() """) testdir.makepyfile(""" import pytest @pytest.mark.anyio async def test_task_group(streams): send1, receive2 = streams await send1.send("hello") assert await receive2.receive() == "hello" """) result = testdir.runpytest_subprocess(*pytest_args) result.assert_outcomes(passed=len(get_all_backends()))
def test_plugin(testdir: Pytester) -> None: testdir.makeconftest(""" import sniffio import pytest from anyio import sleep @pytest.fixture async def async_fixture(): await sleep(0) return sniffio.current_async_library() @pytest.fixture async def some_feature(): yield None await sleep(0) """) testdir.makepyfile(""" import pytest import sniffio from hypothesis import strategies, given from anyio import get_all_backends, sleep @pytest.mark.anyio async def test_marked_test() -> None: # Test that tests marked with @pytest.mark.anyio are run pass @pytest.mark.anyio async def test_async_fixture_from_marked_test(async_fixture): # Test that async functions can use async fixtures assert async_fixture in get_all_backends() def test_async_fixture_from_sync_test(anyio_backend_name, async_fixture): # Test that regular functions can use async fixtures too assert async_fixture == anyio_backend_name @pytest.mark.anyio async def test_skip_inline(some_feature): # Test for github #214 pytest.skip("Test that skipping works") """) result = testdir.runpytest(*pytest_args) result.assert_outcomes(passed=3 * len(get_all_backends()), skipped=len(get_all_backends()))
def test_enter_leave_pdb_hooks_are_called(self, post_mortem, pytester: Pytester) -> None: pytester.makeconftest(""" mypdb = None def pytest_configure(config): config.testing_verification = 'configured' def pytest_enter_pdb(config, pdb): assert config.testing_verification == 'configured' print('enter_pdb_hook') global mypdb mypdb = pdb mypdb.set_attribute = "bar" def pytest_leave_pdb(config, pdb): assert config.testing_verification == 'configured' print('leave_pdb_hook') global mypdb assert mypdb is pdb assert mypdb.set_attribute == "bar" """) p1 = pytester.makepyfile(""" import pytest def test_set_trace(): pytest.set_trace() assert 0 def test_post_mortem(): assert 0 """) if post_mortem: child = pytester.spawn_pytest( str(p1) + " --pdb -s -k test_post_mortem") else: child = pytester.spawn_pytest(str(p1) + " -k test_set_trace") child.expect("enter_pdb_hook") child.sendline("c") if post_mortem: child.expect(r"PDB continue") else: child.expect(r"PDB continue \(IO-capturing resumed\)") child.expect("Captured stdout call") rest = child.read().decode("utf8") assert "leave_pdb_hook" in rest assert "1 failed" in rest self.flush(child)
def test_required_option_help(pytester: Pytester) -> None: pytester.makeconftest("assert 0") x = pytester.mkdir("x") x.joinpath("conftest.py").write_text( textwrap.dedent( """\ def pytest_addoption(parser): parser.addoption("--xyz", action="store_true", required=True) """ ) ) result = pytester.runpytest("-h", x) result.stdout.no_fnmatch_line("*argument --xyz is required*") assert "general:" in result.stdout.str()
def test_issue1073_conftest_special_objects(pytester: Pytester) -> None: pytester.makeconftest("""\ class DontTouchMe(object): def __getattr__(self, x): raise Exception('cant touch me') x = DontTouchMe() """) pytester.makepyfile("""\ def test_some(): pass """) res = pytester.runpytest() assert res.ret == 0
def test_conftest_confcutdir(pytester: Pytester) -> None: pytester.makeconftest("assert 0") x = pytester.mkdir("x") x.joinpath("conftest.py").write_text( textwrap.dedent( """\ def pytest_addoption(parser): parser.addoption("--xyz", action="store_true") """ ) ) result = pytester.runpytest("-h", "--confcutdir=%s" % x, x) result.stdout.fnmatch_lines(["*--xyz*"]) result.stdout.no_fnmatch_line("*warning: could not load initial*")
def test_wrap_session_exit_sessionfinish(returncode: Optional[int], pytester: Pytester) -> None: pytester.makeconftest(""" import pytest def pytest_sessionfinish(): pytest.exit(msg="exit_pytest_sessionfinish", returncode={returncode}) """.format(returncode=returncode)) result = pytester.runpytest() if returncode: assert result.ret == returncode else: assert result.ret == ExitCode.NO_TESTS_COLLECTED assert result.stdout.lines[-1] == "collected 0 items" assert result.stderr.lines == ["Exit: exit_pytest_sessionfinish"]
def test_sessionfinish_with_start(pytester: Pytester) -> None: pytester.makeconftest(""" import os values = [] def pytest_sessionstart(): values.append(os.getcwd()) os.chdir("..") def pytest_sessionfinish(): assert values[0] == os.getcwd() """) res = pytester.runpytest("--collect-only") assert res.ret == ExitCode.NO_TESTS_COLLECTED
def test_pytest_pycollect_module(self, pytester: Pytester) -> None: pytester.makeconftest(""" import pytest class MyModule(pytest.Module): pass def pytest_pycollect_makemodule(path, parent): if path.basename == "test_xyz.py": return MyModule.from_parent(fspath=path, parent=parent) """) pytester.makepyfile("def test_some(): pass") pytester.makepyfile(test_xyz="def test_func(): pass") result = pytester.runpytest("--collect-only") result.stdout.fnmatch_lines( ["*<Module*test_pytest*", "*<MyModule*xyz*"])
def test_cache_show(pytester: Pytester) -> None: result = pytester.runpytest("--cache-show") assert result.ret == 0 result.stdout.fnmatch_lines(["*cache is empty*"]) pytester.makeconftest( """ def pytest_configure(config): config.cache.set("my/name", [1,2,3]) config.cache.set("my/hello", "world") config.cache.set("other/some", {1:2}) dp = config.cache.mkdir("mydb") dp.joinpath("hello").touch() dp.joinpath("world").touch() """ ) result = pytester.runpytest() assert result.ret == 5 # no tests executed result = pytester.runpytest("--cache-show") result.stdout.fnmatch_lines( [ "*cachedir:*", "*- cache values for '[*]' -*", "cache/nodeids contains:", "my/name contains:", " [1, 2, 3]", "other/some contains:", " {*'1': 2}", "*- cache directories for '[*]' -*", "*mydb/hello*length 0*", "*mydb/world*length 0*", ] ) assert result.ret == 0 result = pytester.runpytest("--cache-show", "*/hello") result.stdout.fnmatch_lines( [ "*cachedir:*", "*- cache values for '[*]/hello' -*", "my/hello contains:", " *'world'", "*- cache directories for '[*]/hello' -*", "d/mydb/hello*length 0*", ] ) stdout = result.stdout.str() assert "other/some" not in stdout assert "d/mydb/world" not in stdout assert result.ret == 0
def test_pytest_configure_warning(pytester: Pytester, recwarn) -> None: """Issue 5115.""" pytester.makeconftest(""" def pytest_configure(): import warnings warnings.warn("from pytest_configure") """) result = pytester.runpytest() assert result.ret == 5 assert "INTERNALERROR" not in result.stderr.str() warning = recwarn.pop() assert str(warning.message) == "from pytest_configure"