py.test : Can multiple markers be applied at the test function level?

梦想的初衷 提交于 2019-12-01 00:32:10

问题


I have seen from the pytest docs that we can apply multiple markers at once on the Class or module level. I didn't find documentation for doing it at the test function level. Has anybody done this before with success?

I would like to ideally do this as a list of markers as being done in the above doc for Classes, for example (quoting from the docs):

class TestClass:
    pytestmark = [pytest.mark.webtest, pytest.mark.slowtest]

So, the pytest documentation talks about using pytestmark to specify the markers at the class and module level. However, it doesn't talk about having something similar at the test function level. I would have to specify the markers individually on top of test functions to get them marked with each one of them. This makes the test code look a little clunky with the increasing number of markers on top of test functions.

test_example.py:

pytestmark = [class1, class2]

class TestFeature(TestCase):

    @pytest.mark.marker1
    @pytest.mark.marker2
    @pytest.mark.marker3
    def test_function(self):
        assert True

回答1:


For functions you just repeat the decorator:

@pytest.mark.webtest
@pytest.mark.slowtest
def test_something(...):
    ...

If you want to reuse that for several tests you should remember that decorators are just functions returning decorated thing, so several decorators is just a composition:

def compose_decos(decos):
    def composition(func):
        for deco in reversed(decos):
            func = deco(func)
        return func
    return composition

all_marks = compose_decos(pytest.mark.webtest, pytest.mark.slowtest)

@all_marks
def test_something(...):
    ...

Or you can use general purpose composition such as my funcy library has:

from funcy import compose

all_marks = compose(pytest.mark.webtest, pytest.mark.slowtest)

Note that this way you can compose any decorators, not only pytest marks.




回答2:


Haven't tried this myself. However, from a quick look at the source, I think class MarkDecorator is what you want. Try:

mark_names=["marker1", "marker2", "marker3"]
my_marks = pytest.MarkDecorator(*mark_names)
marked_test_function = my_marks(test_function)

The *mark_names just unpacks mark_names into the constructor arguments of MarkDecorator. MarkDecorator.__call__ then applies the stored marks (self.args) to the parameter, here test_function, to provide a marked test function.

You can also use def unmarked_test_function() ... and test_function=my_marks(unmarked_test_function) so you don't have to change names.

Added explanation: I got this from pytest.mark, which turns out to be a MarkGenerator singleton. MarkGenerator creates MarkDecorator classes, which are then applied as decorators. The above code simulates that process manually, stuffing multiple markers.



来源:https://stackoverflow.com/questions/38335589/py-test-can-multiple-markers-be-applied-at-the-test-function-level

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!