关于python:使用py.test运行测试套件(任意测试集合)

running a test suite (an arbitrary collection of tests) with py.test

我正在使用py.test构建功能测试框架,因此我需要能够指定要运行的确切测试。我了解动态测试集合的优点,但我希望能够先运行测试环境运行状况检查,然后再运行回归测试;该分类并不排除这些集中的测试可用于其他目的。

测试套件将与Jenkins构建项目联系在一起。我正在使用osx,python 2.7.3,py.test 2.3.4。

所以我有一个如下的测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# sample_unittest.py
import unittest, pytest

class TestClass(unittest.TestCase):

    def setUp(self):
        self.testdata = ['apple', 'pear', 'berry']

    def test_first(self):
        assert 'apple' in self.testdata

    def test_second(self):
        assert 'pear' in self.testdata

    def tearDown(self):
        self.testdata = []

def suite():
    suite = unittest.TestSuite()
    suite.addTest(TestClass('test_first'))
    return suite

if __name__ == '__main__':
    unittest.TextTestRunner(verbosity=2).run(suite())

我有一个像这样的测试套件:

1
2
3
4
5
6
7
8
9
10
11
12
13
# suite_regression.py
import unittest, pytest
import functionaltests.sample_unittest as sample_unittest

# set up the imported tests
suite_sample_unittest = sample_unittest.suite()

# create this test suite
suite = unittest.TestSuite()
suite.addTest(suite_sample_unittest)

# run the suite
unittest.TextTestRunner(verbosity=2).run(suite)

如果我从命令行对套件运行以下命令,则test_first会运行(但我没有得到py.test提供的其他信息):

python functionaltests/suite_regression.py -v

如果对套件运行以下命令,则会收集0个测试:

py.test functionaltests/suite_regression.py

如果我针对测试用例运行以下命令,请运行test_first和test_second:

py.test functionaltests/sample_unittest.py -v

我看不到用关键字py.test如何帮助将测试组织到套件中。将测试用例放置在文件夹结构中并使用文件夹选项运行py.test不会让我按功能区域组织测试。

所以我的问题是:

  • 是否有py.test机制以可重用的格式指定任意的测试分组?
  • 有没有办法从py.test使用unittest.TestSuite?
  • 编辑:
    因此,我尝试了py.test标记,该标记使我可以使用任意标签标记测试功能和测试方法,然后在运行时过滤该标签。

    1
    2
    3
    4
    5
    6
    # conftest.py
    import pytest

    # set up custom markers
    regression = pytest.mark.NAME
    health = pytest.mark.NAME

    和我更新的测试用例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    # sample_unittest.py
    import unittest, pytest

    class TestClass(unittest.TestCase):

        def setUp(self):
            self.testdata = ['apple', 'pear', 'berry']

        @pytest.mark.healthcheck
        @pytest.mark.regression
        def test_first(self):
            assert 'apple' in self.testdata

        @pytest.mark.regression
        def test_second(self):
            assert 'pear' in self.testdata

        def tearDown(self):
            self.testdata = []

    def suite():
        suite = unittest.TestSuite()
        suite.addTest(TestClass('test_first'))
        return suite

    if __name__ == '__main__':
        unittest.TextTestRunner(verbosity=2).run(suite())

    因此,运行以下命令将收集并运行test_first:

    py.test functionaltests/sample_unittest.py -v -m healthcheck

    并收集并运行test_first和test_second:

    py.test functionaltests/sample_unittest.py -v -m regression

    回到我的问题:标记是部分解决方案,但是我仍然没有办法控制收集的标记测试的执行。


    我想现在有点晚了,但是我在这里完成了一个带有文档的交互式选择插件:

    https://github.com/tgoodlet/pytest-interactive

    我实际上使用了上面提到的钩子Holger。

    它允许您在收集阶段之后使用IPython选择测试的选择。如果您要这样做,则可以使用切片,下标或制表符完成命令来订购测试。请注意,它是一个交互式工具,旨在在开发期间使用,而对于自动回归运行而言则不是很多。

    对于使用标记的持久排序,我使用了pytest-ordering,它实际上非常有用,尤其是当您在较长的回归套件中具有基线前提测试时。


    在这种情况下,无需使用标记:在py.test测试类上设置@pytest.mark.incremental会将执行顺序强制为声明顺序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # sequential.py
    import pytest

    @pytest.mark.incremental
    class TestSequential:

        def test_first(self):
            print('first')

        def test_second(self):
            print('second')

        def test_third(self):
            print('third')

    现在运行

    1
    pytest -s -v sequential.py

    产生以下输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    =========== test session starts ===========
    collected 3 items

    sequential.py::TestSequential::test_first first
    PASSED
    sequential.py::TestSequential::test_second second
    PASSED
    sequential.py::TestSequential::test_third third
    PASSED
    =========== 3 passed in 0.01 seconds ===========


    当前没有直接的方法来控制测试执行的顺序。 FWIW,有一个插件挂钩pytest_collection_modifyitems,您可以用来实现某些功能。请参阅https://github.com/klrmn/pytest-random/blob/master/random_plugin.py,了解使用该插件实现随机化的插件。