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

Python interface pattern and unit test code coverage

我在一个 python 项目中工作,使用 unittest 进行测试,coverage 进行代码覆盖。
我广泛使用接口模式,我注意到整体代码覆盖率受 "non tested interfaces".
的影响很大 考虑以下因素:

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


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

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

有没有办法忽略来自 coverage 的接口?
由于这是我的第一个 python 项目,我这样做是否完全错误?

我真的不明白将这个 read 方法定义为单条指令有什么意义。如果你不需要它,让它提高 NotImplementedError.

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

the docs 中指定的那样,抽象方法可以具有由 children 和 super() 使用的实现。但在你的情况下,它什么都不做。因此,除非你有充分的理由,否则你还不如让它升 NotImplementedError.

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

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

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

您可以添加一个测试来检查抽象方法 returns 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 装饰器。因为它阻止 class 被实例化,所以我不会引发 NotImplementedError。参见 this other answer.

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

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