如何在pytest中测试类层次结构? [英] How to test a class hierarchy in pytest?

查看:89
本文介绍了如何在pytest中测试类层次结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been using pytest for a while and learnt to love parametrization and fixtures. For the first time, I want to test a number of classes with a branched inheritance structure. Naturally, I would like to reuse test cases for child classes. Say I have the following package structure:

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 包含以下内容:

As outlined in this SO question I can use a fixture to provide an instance of the class being tested. However, when I import a test class from one test module in another it (a) feels like it's not the pytest way and (b) pytest will run all test methods of the imported class plus run them again as part of the inherited test class. Say for example the file test_child.py contained the following:

from test_parent import TestParent


class TestChild(TestParent):

    def test_foo(self):
        pass

    def test_bar(self):
        pass

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

this causes pytest to run the test methods in TestParent once (due to being imported in the module) plus another time as part of TestChild (due to its methods being inherited).

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

So I see two ways: (1) Do not inherit the base test class but just create a fixture so that the current instance is used both for TestParent and TestChild, essentially:

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 中创建一个参数化的fixture,它将所有相关类的实例插入到这些测试方法中.类似的东西:

(2) The other way I see is to not import any test classes but just create a parametrized fixture in test_parent.py that would insert instances of all relevant classes into those test methods. Something like:

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),因为它避免了导入,我什至可以完全跳过测试类.有没有更好的方法?

Thinking about it, I like option (2) much better since it avoids imports and I could even skip test classes altogether. Is there a better way, though?

推荐答案

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

Your original suggestion with class TestChild(TestParent): should work fine. Just avoid importing it under a name which gets collected by pytest. E.g.:

# 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_ 仅在函数或方法时才被视为测试.但是为了避免混淆,这样做很好.

Note that the renaming is not required as test_ is only treated as a test when a function or method. But it's nice to do in order to avoid confusion.

这篇关于如何在pytest中测试类层次结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆