161 lines
4.7 KiB
Plaintext
161 lines
4.7 KiB
Plaintext
|
|
=====================================
|
|
Python test function arguments
|
|
=====================================
|
|
|
|
py.test enables a new way to separate test configuration
|
|
and test setup from actual test code in test functions.
|
|
When it runs a test functions it will lookup function
|
|
arguments by name and provide a value.
|
|
Here is a simple example for such a test function:
|
|
|
|
def test_function(mysetup):
|
|
# work with mysetup
|
|
|
|
To provide a value py.test looks for a ``pytest_funcargs``
|
|
dictionary in the test module, for example::
|
|
|
|
class MySetup:
|
|
def __init__(self, pyfuncitem):
|
|
self.pyfuncitem = pyfuncitem
|
|
pytest_funcargs = {'mysetup': MySetup}
|
|
|
|
This is already enough to run the test. Of course
|
|
up until now our ``mysetup`` does not provide
|
|
much value. But it is now easy to add new
|
|
methods on the ``MySetup`` class that have
|
|
full access to the test collection process.
|
|
|
|
Plugins can register their funcargs via
|
|
the config object, usually upon initial configure::
|
|
|
|
class ConftestPlugin:
|
|
def pytest_configure(self, config):
|
|
config.register_funcargs(mysetup=MySetup)
|
|
|
|
If you provide a "funcarg" from a plugin you can
|
|
easily make methods depend on command line options
|
|
or environment settings. Here is a complete
|
|
example that allows to run tests involving
|
|
an SSH connection if an ssh host is specified::
|
|
|
|
class ConftestPlugin:
|
|
def pytest_addoption(self, parser):
|
|
parser.addoption("--ssh", action="store", default=None,
|
|
help="specify ssh host to run tests with")
|
|
|
|
def pytest_configure(self, config):
|
|
config.register_funcargs(mysetup=MySetup)
|
|
|
|
class MySetup:
|
|
def __init__(self, pyfuncitem):
|
|
self.pyfuncitem = pyfuncitem
|
|
def ssh_gateway(self):
|
|
host = pyfuncitem.config.option.ssh
|
|
if host is None:
|
|
py.test.skip("specify ssh host with --ssh to run this test")
|
|
return py.execnet.SshGateway(host)
|
|
|
|
Now any test functions can use the "mysetup" object, for example::
|
|
|
|
class TestClass:
|
|
def test_function(self, mysetup):
|
|
ssh_gw = mysetup.ssh_gateway()
|
|
# work with ssh_gw
|
|
|
|
Without specifying a command line option the output looks like this::
|
|
|
|
...
|
|
|
|
|
|
Lookup rules
|
|
======================
|
|
|
|
In order to run this test function a value for the
|
|
``mysetup`` needs to be found. Here is how py.test
|
|
finds a matching provider function:
|
|
|
|
1. see if there is a ``pytest_funcargs`` dictionary
|
|
which maps ``mysetup`` to a provider function.
|
|
if so, call the provider function.
|
|
|
|
XXX
|
|
|
|
|
|
|
|
example
|
|
=====================
|
|
|
|
You can run a test file ``test_some.py`` with this content:
|
|
|
|
pytest_funcargs = {'myarg': (lambda pyfuncitem: 42)}
|
|
|
|
def test_something(myarg):
|
|
assert myarg == 42
|
|
|
|
You can also put this on a class:
|
|
|
|
class TestClass:
|
|
pytest_funcargs = {'myarg': (lambda pyfuncitem: 42)}
|
|
|
|
def test_something(self, myarg):
|
|
assert myarg == 42
|
|
|
|
To separate funcarg setup you can also put a funcarg
|
|
definition into a conftest.py::
|
|
|
|
pytest_funcargs = {'myarg': decorate_myarg}
|
|
def decorate_myarg(pyfuncitem):
|
|
result = pyfuncitem.call_next_provider()
|
|
return result + 1
|
|
|
|
for registering funcargs from a plugin, talk to the
|
|
test configuration object like this::
|
|
|
|
class MyPlugin:
|
|
def pytest_configure(self, config):
|
|
config.register_funcargs(
|
|
myarg=decorate_myarg
|
|
)
|
|
|
|
a local helper funcarg for doing acceptance tests maybe
|
|
by running shell commands could look like this::
|
|
|
|
class MyPlugin:
|
|
def pytest_option(self, parser):
|
|
group = parser.addgroup("myproject acceptance tests")
|
|
group.addoption("-A", dest="acceptance", action="store_true",
|
|
help="run (slow) acceptance tests")
|
|
|
|
def pytest_configure(self, config):
|
|
config.register_funcargs(accept=AcceptFuncarg)
|
|
|
|
class AcceptFuncarg:
|
|
def __init__(self, pyfuncitem):
|
|
if not pyfuncitem.config.option.acceptance:
|
|
py.test.skip("specify -A to run acceptance tests")
|
|
self.tmpdir = pyfuncitem.config.maketempdir(pyfuncitem.name)
|
|
self._old = self.tmpdir.chdir()
|
|
pyfuncitem.addfinalizer(self.finalize)
|
|
|
|
def run(self):
|
|
return py.process.cmdexec("echo hello")
|
|
|
|
def finalize(self):
|
|
self._old.chdir()
|
|
# cleanup any other resources
|
|
|
|
and the actual test function example:
|
|
|
|
def test_some_acceptance_aspect(accept):
|
|
accept.tmpdir.mkdir("somesub")
|
|
result = accept.run()
|
|
assert result
|
|
|
|
for registering funcargs from a plugin, talk to the
|
|
test configuration object like this::
|
|
|
|
XXX
|
|
|
|
|