【问题标题】:How to test a class hierarchy in pytest?如何在pytest中测试类层次结构?
【发布时间】:2018-04-10 09:09:50
【问题描述】:

我使用 pytest 已经有一段时间了,并且学会了喜欢参数化和固定装置。第一次,我想测试一些具有分支继承结构的类。自然,我想为子类重用测试用例。假设我有以下包结构:

mock
├── pkg
│   ├── child.py
│   ├── grandchild.py
│   └── parent.py
└── tests
    ├── test_child.py
    ├── test_grandchild.py
    └── test_parent.py

正如this SO question 中所述,我可以使用夹具来提供正在测试的类的实例。但是,当我从另一个测试模块中的一个测试模块导入一个测试类时,它 (a) 感觉它不是 pytest 方式,并且 (b) pytest 将运行导入类的所有测试方法,并作为继承测试类的一部分再次运行它们.例如,文件test_child.py 包含以下内容:

from test_parent import TestParent


class TestChild(TestParent):

    def test_foo(self):
        pass

    def test_bar(self):
        pass

这会导致 pytest 运行 TestParent 中的测试方法一次(由于被导入到模块中)加上另一次作为 TestChild 的一部分(由于其方法被继承)。

所以我看到了两种方法:(1)不继承基测试类,而只是创建一个夹具,以便当前实例同时用于TestParentTestChild,本质上是:

import pytest

from pkg.child import Child
from test_parent import TestParent


@pytest.fixture(scope="class")
def instance():
    return Child()


class TestChild(object):

    def test_foo(self, instance):
        pass

    def test_bar(self, instance):
        pass

(2) 我看到的另一种方法是不导入任何测试类,而只是在test_parent.py 中创建一个参数化夹具,它将所有相关类的实例插入到这些测试方法中。比如:

import pytest

from pkg.parent import Parent
from pkg.child import Child
from pkg.grandchild import GrandChild


@pytest.fixture(scope="class", params=[Parent, Child, GrandChild])
def instance(request):
    return request.param()


class TestParent(object):

    def test_base(self, instance):
        pass

考虑一下,我更喜欢选项 (2),因为它避免了导入,我什至可以完全跳过测试类。不过,有没有更好的方法?

【问题讨论】:

    标签: python inheritance pytest


    【解决方案1】:

    您对class TestChild(TestParent): 的原始建议应该可以正常工作。只是避免以 pytest 收集的名称导入它。例如:

    # test_parent.py
    class TestParent:
    
        def test_parent(self):
            assert True
    

    # test_child.py
    import test_parent as parent  # renaming not required
    
    class TestChild(parent.TestParent):
    
        def test_child(self):
            assert True
    

    运行这个:

    > pytest -v
    ======================== test session starts =========================
    platform linux -- Python 3.6.5rc1, pytest-3.5.0, py-1.5.3, pluggy-0.6.0 -- /home/flub/.virtualenvs/a713d56197da3b03/bin/python3
    cachedir: .pytest_cache
    rootdir: /tmp/sandbox, inifile:
    collected 3 items                                                                                                                                                                                    
    
    test_child.py::TestChild::test_child PASSED                     [ 33%]
    test_child.py::TestChild::test_parent <- test_parent.py PASSED  [ 66%]
    test_parent.py::TestParent::test_parent PASSED                  [100%]
    
    =================== 3 passed in 0.01 seconds =========================
    

    请注意,重命名不是必需的,因为 test_ 仅在函数或方法时被视为测试。但是为了避免混淆,这样做很好。

    【讨论】:

      猜你喜欢
      • 2012-02-11
      • 1970-01-01
      • 1970-01-01
      • 2012-04-30
      • 1970-01-01
      • 1970-01-01
      • 2012-11-07
      • 2011-10-17
      • 1970-01-01
      相关资源
      最近更新 更多