(disabled by default) support for testing pytest and pytest plugins.”””
这里我们先来看一个例子,看看 pytester 是如何帮助我们构建这个集成测试环境的。我们以 pytest 自身的测试代码 test_marker.py 为例,这个是用来测试 mark (标签) 插件的。我们看其中的一个测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
deftest_marked_class_run_twice(testdir): """Test fails file is run twice that contains marked class. See issue#683. """ py_file = testdir.makepyfile( """ import pytest @pytest.mark.parametrize('abc', [1, 2, 3]) class Test1(object): def test_1(self, abc): assert abc in [1, 2, 3] """ ) file_name = os.path.basename(py_file.strpath) rec = testdir.inline_run(file_name, file_name) rec.assertoutcome(passed=6)
这里有几个关键词,我们依次来做下分析介绍,帮助大家理解其中的执行逻辑
testdir 这个 fixture
用 “”” 注释的一段测试用例代码
rec = testdir.inline_run 这个函数调用
TestDir
testdir 是在 pytester 插件实现中定义的一个 fixture
1 2 3 4 5 6 7 8 9 10
@pytest.fixture deftestdir(request: FixtureRequest, tmpdir_factory) -> "Testdir": """ A :class: `TestDir` instance, that can be used to run and test pytest itself. It is particularly useful for testing plugins. It is similar to the `tmpdir` fixture but provides methods which aid in testing pytest itself. """ return Testdir(request, tmpdir_factory)
@pytest.fixture(scope="session") deftmpdir_factory(request: FixtureRequest) -> TempdirFactory: """Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session. """ # Set dynamically by pytest_configure() above. return request.config._tmpdirhandler # type: ignore
This is based on the tmpdir fixture but provides a number of methods which aid with testing pytest itself. Unless :py:meth:chdir is used all methods will use :py:attr:tmpdir as their current working directory.
if lines: source = "\n".join(to_text(x) for x in lines) basename = self._name items.insert(0, (basename, source))
ret = None for basename, value in items: p = self.tmpdir.join(basename).new(ext=ext) p.dirpath().ensure_dir() source = Source(value) source = "\n".join(to_text(line) for line in source.lines) p.write(source.strip().encode(encoding), "wb") if ret isNone: ret = p return ret
defmake_hook_recorder(self, pluginmanager): """Create a new :py:class:`HookRecorder` for a PluginManager.""" pluginmanager.reprec = reprec = HookRecorder(pluginmanager) self.request.addfinalizer(reprec.finish_recording) return repre
classHookRecorder: """Record all hooks called in a plugin manager. This wraps all the hook calls in the plugin manager, recording each call before propagating the normal calls. """