Pytest无法通过标记skipif跳过类中的testcase

Nit*_*esh 5 python testing unit-testing pytest

我正在使用pytest框架,并希望根据某些条件跳过testcase.下面的代码不会跳过测试用例.

import pytest
class TEST:
    @pytest.fixture(scope="function", autouse=True)
    def func_fixture(self):
        return "fail"

    @pytest.mark.skipif("self.func_fixture=='fail'")
    def test_setting_value(self):
        print("Hello I am in testcase")
Run Code Online (Sandbox Code Playgroud)

运行时,它表示0个测试用例已执行.

func_fixture对于测试套件非常重要.它在开始测试之前执行许多先决条件.

如果我删除类,并使用相同的语法添加其余的函数(删除self后),它可以工作.不知道为什么它在课堂上失败了

hoe*_*ing 2

长话短说

您可以跳过测试本身内的条件;跳到答案末尾的建议。使用您的示例代码,skipIf不可能通过标记跳过测试。


首先,让我澄清以下几点:如果你定义了一个foo返回值的自动使用装置,并不意味着测试类将自动成为一个属性foo

class TestCls:

    @pytest.fixture(autouse=True)
    def fix(self):
        return 'foo'

    def test_fix(self):
        assert self.fix == 'foo'
Run Code Online (Sandbox Code Playgroud)

运行此测试将失败:

    def test_fix(self):
>       assert self.fix == 'foo'
E       AssertionError: assert <bound method TestCls.fix of <test_bacon.TestCls object at 0x105670cf8>> == 'foo'
E        +  where <bound method TestCls.fix of <test_bacon.TestCls object at 0x105670cf8>> = <test_bacon.TestCls object at 0x105670cf8>.fix
Run Code Online (Sandbox Code Playgroud)

那是因为这不是固定装置的工作原理。如果固定装置返回某些内容,则如果在测试函数中添加与固定装置名称相同的参数,则可以访问其返回值。这是类的问题,因为您无法将固定装置作为参数传递给测试类方法;总体而言,对测试的支持pytest是有限的。根本不知道为什么你需要上课;您可以仅使用固定装置在多个测试功能之间完美共享状态。整个目的pytest是使测试类过时,其中每个测试方法都可以重新设计为测试函数。

如果需要在类中的测试之间共享值,则需要将其分配给夹具中测试类实例的某些属性。下面的例子将会通过:

class TestCls:

    @pytest.fixture(autouse=True)
    def fix(self):
        self._fix = 'foo'

    def test_fix(self):
        assert self._fix == 'foo'
Run Code Online (Sandbox Code Playgroud)

因此,实际返回某些内容的固定装置在测试类中是无用的,因为无法将固定装置作为测试类方法中的参数传递。

不知道为什么在课堂上失败

这是因为标记是在测试集合上评估的,以过滤掉应该执行的测试,并且只有在收集测试并准备好运行之后才会执行固定装置。这意味着你想要的东西是不可能的。您将无法将任何夹具结果传递给skipif标记,因为尚未评估任何夹具。检查执行顺序:

@pytest.fixture(autouse=True)
def myfixture():
    print('myfixture called')


class TestCls:

    @pytest.fixture(autouse=True)
    def myclassfixture(self):
        print('TestCls.myclassfixture called')

    @pytest.mark.skipif('print(os.linesep, "TestCls.test_spam skipif called")', reason='something')
    def test_spam(self):
        print('TestCls.test_spam called')
Run Code Online (Sandbox Code Playgroud)

输出:

TestCls.test_spam skipif called
myfixture called
TestCls.myclassfixture called
TestCls.test_spam called
Run Code Online (Sandbox Code Playgroud)

另请注意,测试类实例在 中不可用skipif,仅在模块级别定义(类、函数和全局变量):

class Tests:

    @pytest.mark.skipif('print(os.linesep, "globals:", globals().keys(), os.linesep, "locals:", locals().keys())', reason='something')
    def test_spam(self):
        pass
Run Code Online (Sandbox Code Playgroud)

输出:

test_spam.py::TestCls::test_spam
 globals: dict_keys(['os', 'sys', 'platform', 'config', '__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', '@py_builtins', '@pytest_ar', 'pytest', 'myfixture', 'TestCls'])
 locals: dict_keys(['os', 'sys', 'platform', 'config', '__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', '@py_builtins', '@pytest_ar', 'pytest', 'myfixture', 'TestCls'])
Run Code Online (Sandbox Code Playgroud)

建议

除了skip/skipIf标记之外,您还可以在测试本身内显式跳过测试:

class TestCls:

    @pytest.fixture(autouse=True)
    def myfixture(self):
        self.status = 'fail'

    def test_eggs(self):
        if self.status == 'fail':
            pytest.skip('self.status is set to "fail"')
        assert False
Run Code Online (Sandbox Code Playgroud)

如果运行,则跳过测试:

test_eggs.py::TestCls::test_eggs SKIPPED
Run Code Online (Sandbox Code Playgroud)