Python 接口(interface)模式和单元测试代码覆盖率

标签 python unit-testing code-coverage python-unittest

我在一个 python 项目中工作,使用 unittest 进行测试,同时使用 coverage 进行代码覆盖。
我广泛使用接口(interface)模式,我注意到整体代码覆盖率受到“未测试接口(interface)”的严重影响。
请考虑以下事项:

class IReader(object):
    @abstractmethod
    def read(self):
        pass


class Reader(IReader):
    def read(self):
        # whatever

我测试了 Reader 但(显然)我没有测试 IReader 所以 pass 指令被标记为未被测试覆盖。

有没有办法忽略 coverage 中的接口(interface)?
由于这是我的第一个 Python 项目之一,我这样做是否完全错误?

最佳答案

我真的不明白将此 read 方法定义为单条指令有什么意义。如果您不需要它,让它引发 NotImplementedError

class IReader(object):
    @abstractmethod
    def read(self):
        raise NotImplementedError

the docs 中所述, 一个抽象方法可以有一个实现,由 super() 的 child 使用。但在你的情况下,它什么都不做。因此,除非你有充分的理由,否则你不妨让它引发 NotImplementedError

(可以说,一个很好的理由可能是您的所有 child 出于某种原因调用 super().my_method() 的模式,因此您需要抽象类中所有方法的实现。)

如何从覆盖率报告中排除抽象方法

无论如何,测试覆盖率只是您构建的一个指标:您要测试的代码中您实际测试的部分。定义“您要测试的代码”由您决定。

您可以添加一个测试来检查抽象方法是否返回 NotImplementedError 或只是 passes,如果您对此感兴趣的话。

或者你可能会认为(这似乎是合理的)测试这个是没有意义的,在这种情况下 excluding覆盖率报告中的方法 #pragma: no cover 似乎是可行的方法:

class IReader(object):  #pragma: no cover
    @abstractmethod
    def read(self):
        pass

上面链接的文档页面显示了如何将所有 NotImplementedError 方法添加到您的配置文件中:

[report]
exclude_lines =
    pragma: no cover
    raise NotImplementedError

这样您就不必为每个抽象方法添加 pragma


2020 年编辑

我刚刚注意到@abstractmethod 装饰器。因为它阻止类被实例化,所以我不会引发 NotImplementedError。参见 this other answer.

我只是将方法留空。从语法上讲,文档字符串就足够了

class IReader(object):
    @abstractmethod
    def read(self):
        """Read data"""

关于Python 接口(interface)模式和单元测试代码覆盖率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42199671/

相关文章:

python - 如何使用 python 将 utf-8 字符正确插入 MySQL 表

java - 有哪些好的免费解析程序?

python - 用于桌面应用程序的 Camelot

unit-testing - 使用 zend test dbadapter 和 zend db 表摘要

c# - 从 Visual Studio 2015 中的代码覆盖率中排除自动属性

python - django.core.exceptions.ImproperlyConfigured : Requested setting LOGGING_CONFIG, 但未配置设置

unit-testing - Vue.js 过滤器和测试

c++ - gcov 报告的析构函数中的分支是什么?

c++ - 代码覆盖警告垃圾邮件输出

PHPSpec:输出格式的配置