【问题标题】:How to test a class' inherited methods in pytest如何在pytest中测试一个类的继承方法
【发布时间】:2017-09-04 15:46:03
【问题描述】:

house.py:

class House:
    def is_habitable(self):
        return True

    def is_on_the_ground(self):
        return True

conftest.py:

import pytest
from house import House


@pytest.fixture(scope='class')
def house():
    return House()

test_house.py:

class TestHouse:
    def test_habitability(self, house):
        assert house.is_habitable()

    def test_groundedness(self, house):
        assert house.is_on_the_ground()

到目前为止,一切都在测试中。

现在我添加一个子类并覆盖house.py 中的一个方法:

class House:
    def is_habitable(self):
        return True

    def is_on_the_ground(self):
        return True


class TreeHouse(House):
    def is_on_the_ground(self):
        return False

我还在conftest.py 中为该类添加了一个新夹具:

import pytest
from house import House
from house import TreeHouse


@pytest.fixture(scope='class')
def house():
    return House()


@pytest.fixture(scope='class')
def tree_house():
    return TreeHouse()

我在test_house.py中为树屋添加了一个新的测试类:

class TestHouse:
    def test_habitability(self, house):
        assert house.is_habitable()

    def test_groundedness(self, house):
        assert house.is_on_the_ground()


class TestTreeHouse:
    def test_groundedness(self, tree_house):
        assert not tree_house.is_on_the_ground()

此时,代码可以工作,但有些情况没有经过测试。例如,为了完整,我需要再次测试从House 中继承的方法TreeHouse

TestHouse 重写相同的测试不会 DRY。

如何在不重复代码的情况下测试TreeHouse(本例为is_habitable)的继承方法?

我想要重新测试TreeHouse 与它的超类运行的相同测试,但不适用于新的或覆盖的方法/属性。

经过一些研究,我发现了相互矛盾的来源。在深入研究 pytest 文档后,我无法理解适用于这种情况的内容。

我对 pytest 方法很感兴趣。请参考文档并在此处解释如何应用。

【问题讨论】:

  • 你的最后一行应该是assert not tree_house.is_on_the_ground()
  • 感谢@PaulH 的编辑
  • @PaulH 我想我也可以摆脱其他断言中的== True
  • 是的。 assert not tree_house.is_on_the_ground() 解决了你的问题吗?应该处理的事情
  • @Bastian 另一个是如果非覆盖方法称为覆盖方法,有时我在查看人们的示例时会得到隧道视野;)

标签: python pytest


【解决方案1】:

一种方法是对所有测试方法使用夹具名称house(即使它正在测试TreeHouse)和override its value in each test context

class TestTreeHouse(TestHouse):
    @pytest.fixture
    def house(self, tree_house):
        return tree_house

    def test_groundedness(self, house):
        assert not house.is_on_the_ground()

还要注意TestTreeHouse 继承自TestHouse。由于pytest merely enumerates methods of classes(即没有使用@pytest.test() 装饰器完成的“注册”),在TestHouse 中定义的所有测试都将在它的子类中发现,无需任何进一步的干预。

【讨论】:

  • 我喜欢这个答案。关于这个答案:stackoverflow.com/a/44431292/1075374 虽然,据说 pytest 禁止类层次结构,尽管链接没有解释它。您对此有何看法?
  • 我试过了,但由于某种原因self 迷路了。 TestTreeHouse.test_habitability --> TypeError: is_habitable() missing 1 required positional argument: 'self'。第二次测试也会发生同样的事情。有什么想法吗?
  • 也许您正在从tree_house 夹具返回类对象 TreeHouse,而不是类的实例:TreeHouse()
  • 对于类层次结构,pytest 跳过定义了 __init__ 的类;它不禁止继承。我无法找到做出该决定的原因的记录,但this comment 建议一个原因是因为 pytest 无法向 __init__ 提供参数,因此定义该方法可能是一个错误。传统智慧似乎是“使用固定装置”,尽管我也没有找到记录:P
  • 你说得对,我传递的是类而不是实例。非常感谢您的研究,非常感谢。
【解决方案2】:

您可以使用pytest parameterization 将多个参数传递给同一个测试,在这种情况下,参数很可能是被测试的类。

【讨论】:

  • 感谢您的链接。我使用参数来重复使用不同参数/参数的测试。但我看不出这在这种情况下会如何运作。您是否愿意通过澄清和显示一些工作代码来进一步扩展您的答案,而不仅仅是指向文档的链接?
猜你喜欢
  • 2021-11-30
  • 1970-01-01
  • 2015-09-19
  • 2021-11-30
  • 2021-02-02
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多