【问题标题】:Stricter Reporting of Python Code Coverage更严格的 Python 代码覆盖率报告
【发布时间】:2017-04-01 22:34:50
【问题描述】:

假设我的项目中有两个 Python 模块:

/project
  /module1
    __init__.py [Empty]
    class1.py
  /module2
    __init__.py [Empty]
    class2.py

Class1 有一些功能,但最重要的是doEverythingAndGetData()。让我们假设它在执行几个内部函数时返回一个数字。

现在假设Class2 使用Class1,然后实现了进一步的功能。 Class2 只有两个功能 - __init__foo()

def foo(self):
    #Create an instance of Class1
    class1 = Class1()

    #Get some information using class1
    data = class1.doEverythingAndGetData()

    #Do some logic on the data, it doesn't matter
    result = (data + 10) * 2

    #Return the result
    return result

现在我想为 Class2 编写一个单元测试,涵盖 foo()

def test_Class2_foo():
    #Create the Class2 object
    class2 = Class2()

    #Get the result
    bar = class2.foo()

    #Compare the value
    expectedBar = 1337
    assert expectedBar == bar, "Mismatch! {} != {}".format(expectedBar, bar)

这个单元测试是为项目编写的唯一一个。我们运行单元测试并生成代码覆盖率报告。

检查代码覆盖率报告后,我们将看到Class2 被很好地覆盖,因为我们已经进行了单元测试并且它正在做它应该做的事情。太棒了!

然而,我们也注意到Class1 也被很好地覆盖,因为单元测试 覆盖了class1.doEverythingAndGetData() 及其任何底层功能。我们的报告显示了整个项目的精彩报​​道!将它发送给 PO,让我们早日度过一个周末!

虽然这具有误导性。我真正希望报告显示的是 Class2 被覆盖,因为我们已经编写了一个可靠地覆盖模块的单元测试。我希望它显示 Class1 被覆盖,因为我们没有任何单元测试来检查它的内部功能。它只是假设 Class1 工作正常,如果单元测试失败,如果 Class1 出错,它的描述将不会很有帮助也不透明。

所以,为了简化:

  • Class2 已通过单元测试适当覆盖
  • Class1没有直接覆盖,使项目面临风险
  • 运行单元测试并生成代码覆盖率报告时,它错误地显示两个模块都经过测试
  • 相反,我希望报告显示Class2 被覆盖,因为foo() 被测试显式调用,而Class1 未被覆盖,因为它的函数在Class2.foo() 中被调用

这导致我提出以下问题:

  1. 有没有办法防止在报道报告中发生这种情况?
  2. 如果有的话,用什么术语来指代这种类型的保险?
  3. 是否有特定的编码模式有助于防止此问题?

谢谢!

【问题讨论】:

  • 您需要向class1.doEverythingAndGetData() 提供一个假号码。因此,doEverythingAndGetData() 函数永远不会被调用,它只是返回一个值。这称为unittest.mock

标签: python unit-testing report code-coverage


【解决方案1】:

您需要mock 来自class1.doEverythingAndGetData() 的数据。在您当前的实现中,每当您调用class2 的单元测试时,该函数内的实际 代码都会运行。这样的事情会帮助你,

from mock import patch
import class1

@patch('class1.doEverythingAndGetData')
def test_Class2_foo(self, doEverythingAndGetData):
    # Let's assume we are mocking 10 as the return value
    doEverythingAndGetData.return_value = 10

    class2 = Class2()

    # This will take mocked value in its implementation
    bar = class2.foo()

    #Compare the value
    expectedBar = 1337
    assert expectedBar == bar, "Mismatch! {} != {}".format(expectedBar, bar)

现在您可以为class1.doEverythingAndGetData() 编写单独的unittest 并获得正确的覆盖率报告!

所以回答你的 3 个问题,

有没有办法在覆盖率报告中防止这种情况发生?

是否有特定的编码模式有助于防止此问题?

是的!使用mock

如果有的话,用来指代此类保险的术语是什么?

从某种意义上说,您所做的可以参考integration 测试,您可以在其中针对一系列输入组合测试多个函数。另一方面,在unit 测试中,您测试每个 函数并尝试查看其工作,而不关心依赖函数是否工作。

【讨论】:

  • 您好,感谢您的详细回复。我会尝试这个解决方案,看看它是否符合我的需要,但它看起来应该!但是,假设class1.doEverythingAndGetData() 返回一个比简单的10 复杂得多的对象。对于这种情况,这是否同样适用?
  • 是的,您需要相应地模拟数据。尝试进行多个单元测试,模拟不同的代表性数据
猜你喜欢
  • 2014-08-21
  • 1970-01-01
  • 2014-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 2012-08-23
相关资源
最近更新 更多