Python 自动检测测试耦合

Python 自动检测测试耦合,python,django,testing,pytest,nose,Python,Django,Testing,Pytest,Nose,对于Python/Django应用程序,我们有一个包含1500多个测试的大型测试代码库。大多数测试用于为项目模型生成数据 目前,我们正在使用,但可以切换到 问题是,在运行部分测试、组合测试时,我们不时会遇到意外的测试失败,这些失败在单独运行所有测试或这些测试时不会重现 看起来测试实际上是耦合的 问题:是否可以自动检测项目中的所有耦合测试 我目前的想法是以不同的随机组合或顺序运行所有测试,并报告失败,可以nose或py.test帮助吗?要得到明确的答案,您必须在与其他测试完全隔离的情况下运行每个测

对于Python/Django应用程序,我们有一个包含1500多个测试的大型测试代码库。大多数测试用于为项目模型生成数据

目前,我们正在使用,但可以切换到

问题是,在运行部分测试、组合测试时,我们不时会遇到意外的测试失败,这些失败在单独运行所有测试或这些测试时不会重现

看起来测试实际上是耦合的

问题:是否可以自动检测项目中的所有耦合测试


我目前的想法是以不同的随机组合或顺序运行所有测试,并报告失败,可以
nose
py.test
帮助吗?

要得到明确的答案,您必须在与其他测试完全隔离的情况下运行每个测试

使用我使用的
pytest
,您可以实现一个脚本,首先使用
--仅收集
运行它,然后使用返回的测试节点ID为每个节点启动单独的
pytest
运行。 对于1500个测试来说,这需要一段时间,但只要您完全重新创建,它就可以完成这项工作 每次单独测试之间系统的状态

为了得到一个大致的答案,您可以尝试以随机顺序运行测试,看看有多少开始失败。我最近有一个类似的问题,所以我尝试了两个
pytest
插件--
pytest random
pytest random

从这两个方面来看,
pytest randoy
看起来更成熟,甚至通过接受
seed
参数来支持重复某个顺序

这些插件在随机化测试顺序方面做得很好,但是对于大型测试套件来说,完全随机化可能不是很可行,因为这样会有太多失败的测试,并且不知道从哪里开始

我编写了自己的插件,允许我控制测试可以随机更改顺序的级别(模块、包或全局)。它被称为
pytest随机顺序

更新。在您的问题中,您说单独运行测试时无法再现故障。可能是您没有完全为单个测试运行重新创建环境。我认为有些测试让州变脏是可以的。每个测试用例都有责任根据需要设置环境,而不必在事后进行清理,因为这会导致后续测试的性能开销,或者只是因为这样做的负担


如果测试X作为更大测试套件的一部分失败,然后在单独运行时没有失败,则此测试X在设置测试环境方面做得不够好。

由于您已经在使用
nosetests
框架,也许您可以随机使用
nose
()以随机顺序运行测试用例

每次使用
nose random
运行nose测试时,每次运行都会使用随机种子进行标记,您可以使用该种子重复运行测试的相同顺序

因此,您可以使用该插件多次运行测试用例,并记录随机种子。每当您看到某个特定顺序的任何失败时,您总是可以通过使用随机种子运行它们来重现它们

理想情况下,除非运行1500个测试的所有组合(即2^1500-1),否则不可能识别测试相关性和失败

因此,养成一种习惯,在运行测试时始终启用随机。在某个时刻,您将遇到失败并继续运行它们,直到您捕获尽可能多的失败

除非故障捕捉到了产品的真正bug,否则修复它们并尽可能减少测试依赖性始终是一个好习惯。这将保持测试结果的一致性,您始终可以独立运行和验证测试用例,并确保该场景下产品的质量


希望这会有所帮助,这就是我们在工作场所所做的,以实现与您试图实现的完全相同的情况。

当测试未正确破坏其环境时,会发生这种情况

Ie:在测试的设置阶段,在测试数据库中创建一些对象,可能写入一些文件,打开网络连接,等等,但没有正确重置状态,从而将信息传递给后续测试,这些测试可能会由于对输入数据的错误假设而失败

与其将重点放在测试之间的耦合上(在上述情况下,这将有点没有意义,因为这可能取决于它们运行的顺序),不如运行一个测试每个测试的拆卸例程的例程

这可以通过包装原始测试类并重写teardown函数来实现,以包含某种类型的通用测试,该测试环境已针对给定测试正确重置

比如:

class NewTestClass(OriginalTestClass):
   ...

    def tearDown(self, *args, **kwargs):
        super(NewTestClass, self).tearDown(*args, **kwargs)
        assert self.check_test_env_reset() is True, "IM A POLLUTER"
name = factory.Sequence(lambda n: 'alecxe-{0}'.format(n))
然后在测试文件中,将原始测试类的导入语句替换为新的:

# old import statement for OriginalTestClass
from new_test_class import NewTestclass as OriginalTestClass
随后进行的测试应导致导致污染的测试失败

另一方面,如果您希望允许测试有点脏,那么您可以将问题视为失败测试的测试环境的错误设置

从后面的角度来看,失败的测试是写得很糟糕的测试,需要单独修复


这两种观点在一定程度上是阴阳的,你可以采用任何一种观点。如果可能的话,我倾向于后者,因为它更健壮。

我在Django的一个大型项目中解决了类似的问题,该项目也使用了nose runner和factory boy。我无法告诉您如何像所问的问题那样自动检测测试耦合,但我有事后诸葛亮