Can I use a pytest fixture in the condition of my skipif logic?
Asked Answered
G

2

6

I am trying to use a pytest fixture (scope=module) in a class skipif decorator, but I am getting an error saying the fixture is not defined. Is this possible?

conftest.py has a fixture with module scope called 'target' that returns a CurrentTarget object. The CurrentTarget object has a function isCommandSupported. test_mytest.py has a class Test_MyTestClass that contains a dozen test functions. I want to skip all the tests in Test_MyTestClass based on if the fixture target.isCommandSupported so I decorate Test_MyTestClass with skipif like:

@pytest.mark.skipif(not target.isCommandSupprted('commandA), reason=command not supported')
class Test_MyTestClass:
...

I get this error: NameError: name 'target' is not defined

If I try:

@pytest.mark.skipif(not pytest.config.getvalue('tgt').isCommandSupprted('commandA), reason=command not supported')
class Test_MyTestClass:
...

I get this error: AttributeError: 'function' object has no attribute 'isCommandSupprted'

Garrulity answered 3/10, 2013 at 20:54 Comment(3)
Is there a better place to ask this question?Garrulity
I have seen Holger Krekel answer here, but he normally points to the freenode chat for support questions. pytest.org/latest/contact.htmlSerpentine
I stumbled upon the same issue. Did you find a solution to the issue?Extensible
T
7

The reason you get an error in the first case is that pytest injects fixtures, so they become available in your test functions via function parameters. They are never imported into higher scope.

The reason you get the AttributeError is that fixtures are functions and are evaluated at first (or each) use. So, when you get it through pytest.config it's still a function. This is the same reason the other answer will fail - if you import it, you're importing the fixture function, not it's result.

There is no direct way of doing what you want, but you can work around it with an extra fixture:

@pytest.fixture(scope='module')
def check_unsupported(target):
  if not target.isCommandSupported('commandA'):
    pytest.skip('command not supported')

@pytest.mark.usefixtures('check_unsupported')
def test_one():
  pass

def test_two(check_unsupported):
  pass
Toft answered 18/4, 2018 at 0:43 Comment(1)
Could you add autouse=True in the check_unsupported fixture definition? Then you would not have to actually use the fixture in any test of the module?Glowing
K
1

You can import target from conftest like so:

from conftest import target

Then, you can use it in pytest.mark.skipif as you were intending in your example.

@pytest.mark.skipif(not target.isCommandSupported('commandA'), reason='command not supported')
def Test_MyTestClass:

If you needed to repeat the same pytest.mark.skipif logic across several tests and wanted to avoid copy-pasting, a simple decorator will help:

check_unsupported = pytest.mark.skipif(not target.isCommandSupported('commandA'),
                                       reason='command not supported')

@check_unsupported
def test_one():
    pass

@check_unsupported
def test_two():
    pass
Kinase answered 1/9, 2016 at 18:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.