Skipping Tests
Pytest filtering options are used to run only the desired tests, but it may be useful to skip a test based on some external condition: for example if the product was built with a certain feature or not. If the feature is not supported, tests that are using this feature must be skipped.
It is not possible to accomplish this with the built-in pytest.mark.skipif
marker since it is evaluated too soon and only takes expressions, it does not
provide access to the fixtures. However, pytest-mh provides alternative
solutions.
See also
Every project has its own specifics and it is not possible to implement generic feature detection and provide it out of the box. ldap.features property used in these examples is not part of pytest-mh. To see tips on how to implement feature detection for your project, see Features Detection.
Skipping individual tests
It is possible to skip individual tests with pytest.mark.require marker.
This marker takes a callable as parameter, if the callable evaluates to True
the test is run. If it evaluates to False, the test is skipped.
Parameters of the callable are all fixtures that are available to the test,
including all MultihostRole objects required by the test, that
is all dynamic fixtures defined by the topology.
Warning
The skip condition is evaluated before test setup is performed to avoid complex setup and teardown for a test that is going to be skipped.
Keep this in mind when accessing the role objects, since the role and its utilities setup method has not yet been called, therefore some properties may not be correctly initialized. It is up to you to make sure that you only access the properties that have been already set in your code.
However, it is perfectly fine to run commands and access properties that do not depend on the setup.
1# Use a simple lambda function
2@pytest.mark.topology(KnownTopology.LDAP)
3@pytest.mark.require(
4 lambda ldap: "password_policy" in ldap.features,
5 "Server is not built with password policy support"
6)
7def test_skip__lambda(client: Client, ldap: LDAP):
8 pass
9
10
11# Use a defined function
12def require_password_policy(ldap: LDAP):
13 return "password_policy" in ldap.features
14
15@pytest.mark.topology(KnownTopology.LDAP)
16@pytest.mark.require(
17 require_password_policy,
18 "Server is not built with password policy support"
19)
20def test_skip__function(client: Client, ldap: LDAP):
21 pass
22
23
24# Use a defined function that also returns a reason in a tuple
25def require_password_policy(ldap: LDAP):
26 result = "password_policy" in ldap.features
27 reason = "Server is not built with password policy support"
28
29 return result, reason
30
31@pytest.mark.topology(KnownTopology.LDAP)
32@pytest.mark.require.with_args(require_password_policy)
33def test_skip__function_and_reason(client: Client, ldap: LDAP):
34 pass
Note
Notice the usage of with_args in the third example
test_skip__function_and_reason. Pytest marker does not
allow single function as an argument and it must be worked
around by using with_args.
See pytest documentation for more information:
pytest.MarkDecorator.with_args()
tests/test_passkey.py::test_skip__lambda (ldap) SKIPPED (Server is not built with password policy support)
tests/test_passkey.py::test_skip__function (ldap) SKIPPED (Server is not built with password policy support)
tests/test_passkey.py::test_skip__function_and_reason (ldap) SKIPPED (Server is not built with password policy support)
Skipping topology
Sometimes, it is not possible to run any tests from specific topology even
though all hosts and roles required by the topology are available – for example
when your program was not built with functionality required to correctly setup
the topology. It is possible to achieve this by setting a skip condition by
overriding the skip() method of
TopologyController.
All dynamic fixtures defined by the topology are passed to the method, but this
time they are instances of MultihostHost instead of
MultihostRole since the role objects are only created for
tests and are not available at this point.
Warning
The skip condition is evaluated before topology setup is performed to avoid complex setup and teardown for tests that are going to be skipped.
Keep this in mind when accessing the host objects, since the hosts and its utilities setup method has not yet been called, therefore some properties may not be correctly initialized. It is up to you to make sure that you only access the properties that have been already set in your code.
However, it is perfectly fine to run commands and access properties that do not depend on the setup.
class PasswordPolicyTopology(TopologyController):
def skip(self, ldap: LDAPHost) -> str | None:
if "password_policy" not in ldap.features:
# Return reason to skip the tests
return "Server is not built with password policy support"
# Return None to run the tests
return None
tests/test_passkey.py::test_skip__lambda (ldap) SKIPPED (Server is not built with password policy support)
tests/test_passkey.py::test_skip__function (ldap) SKIPPED (Server is not built with password policy support)
tests/test_passkey.py::test_skip__function_and_reason (ldap) SKIPPED (Server is not built with password policy support)