【问题标题】:How to test class methods "independently" in Python如何在 Python 中“独立”测试类方法
【发布时间】:2023-02-26 22:25:20
【问题描述】:

我正在努力“独立”地测试类方法。

说,我有这个类:

class Counter:
    def __init__(self, start = 0):
        self.number = start

    def increase(self):
        self.number += 1

我如何明智地测试方法increase()

前段时间,一位高级开发人员告诉我(也许我误解了)我应该独立测试我的方法,这样一来,如果类的某些部分发生变化,我的方法仍然可以测试 OK。

这导致我以一种稍微麻烦的方式测试方法:

# Using pytest here

def test_increase():
    class MockCounter:
        def __init__(self):
            self.number = 0

    x = MockCounter()
    Counter.increase(x)
    assert x.number == 1

在哪里,基本上:

  • 我用MockCounter 模拟类Counter(所以类Counter 不是可能破坏我的测试的依赖项);
  • 我调用该方法进行测试,因为它是一个静态方法。

它有效,但我觉得我在这里误解了很多。

我错了什么?

【问题讨论】:

  • 尝试使方法测试独立于构造函数是不值得的。如果构造函数中断,希望构造函数的测试能够捕捉到它。
  • 不要嘲笑你应该测试的东西的一部分。当然,如果 __init__ 更改为默认情况下 start = 1 那么您的测试将失败,但是如果您断言行为相反 - 在调用 increase 之后 number 属性应该是比以前高一个,不仅仅是1。这样你使用的是真正的类,但如果出现问题,则可以很好地确定问题所在。

标签: python python-3.x pytest


【解决方案1】:

您需要考虑什么样的更改会导致您的测试失败。例如,以当前的实现为例:

class Counter:
    def __init__(self, start = 0):
        self.number = start

    def increase(self):
        self.number += 1

你可以简单地测试类:

def test_increase():
    counter = Counter()
    counter.increase()
    assert counter.number == 1

什么样的变化会导致该测试因假阴性而失败?更改默认值如何:

class Counter:
    def __init__(self, start = 1):
                             # ^ pre-increased for your convenience 
        self.number = start

    def increase(self):
        self.number += 1

assert counter.number == 1 现在失败了,因为它实际上是2,但是increase 方法没有改变并且仍然正常工作.假设您有另一个测试,例如:

def test_default_value():
    counter = Counter()
    assert counter.number == 0

你现在有失败的测试,一个说默认值是错误的,另一个说 increase 方法不起作用。在这个简单的例子中,很明显后者是由前者引起的并且是假阴性,但在更大更复杂的类中,更好地确定给定问题的实际位置确实很有帮助,这就是导致建议独立测试方法。

但是,您不想像您目前对MockCounter 那样模拟您应该测试的部分,因为练习的目的是增加您对测试的信心实际执行而不是测试替身(保留测试替身协作对象,而不是被测对象的一部分)。在最坏的情况下,你最终得到的测试是仅有的运动测试加倍,给人一种对实际可能有效或无效的实施的错误信心。

因此,让我们根据不变量重新构造所需的行为。调用increase后,number属性不应该一直是1,应该是比以前高一个.在对上述变化具有弹性的测试中表达这一点:

  • 在增加之前存储起始值并与之比较:

    def test_increase():
        counter = Counter()
        before = counter.number
        counter.increase()
        assert counter.number == before + 1  # now 2, but that's irrelevant here
    
  • 或者,您可以考虑 __init__ 中的默认值与 increase 方法的行为无关,并在测试中使用明确的起点:

    def test_increase():
        counter = Counter(0)
        counter.increase()
        assert counter.number == 1
    

无论哪种方式,您都可以获得更强大的测试,而不必引入笨拙的部分模拟。

【讨论】:

  • 现在我很清楚了,谢谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-01
相关资源
最近更新 更多