我在一个 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
或只是 pass
es,如果您对此感兴趣的话。
或者你可能会认为(这似乎是合理的)测试这个是没有意义的,在这种情况下 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/