相互隔离最危险的测试

人气:1,176 发布:2022-10-16 标签: python unit-testing testing pytest fixtures

问题描述

我正在从事一个快速发展的Python项目。最近,我们的测试套件开始变得有些难以管理。当它们所在的模块以错误的顺序执行时,有些测试会失败,尽管它们看起来隔离得很好。

我发现了一些关于这方面的其他问题,但他们关心的是灯具:

Pytest fixtures interfering with each other

test isolation between pytest-hypothesis runs

虽然我们也在使用装置,但我不认为问题出在它们身上,但更有可能的是,我们使用的库中的类的内部状态会被测试运行更改,例如被mockito-python更改。

我最初来自Java世界,在那里这种情况不会发生,除非您显式地使您的测试相互依赖,或者做一些疯狂和不寻常的事情。在Python中遵循相同的实践集导致了这些问题,所以我意识到我可能遗漏了一些重要的Python测试开发规则。

是否可以通知pytest在各个模块运行之间删除/还原/重新初始化所有类的内部状态?

如果没有,我们在测试开发期间应该遵循哪些规则来防止这些问题?

编辑:我们发现的问题之一是,我们在测试文件中的顶级设置了一些对象,这些对象是由mockito-python创建的。执行测试时,首先导入所有文件,然后执行测试。发生的情况是,一个测试调用mockito.unstub(),它删除moockito的模拟注册表中的所有模拟。因此,当测试实际执行时,另一个测试已经拆除了它的模拟。这种行为非常违反直觉,尤其是对于没有经验的开发人员。

推荐答案

在Python中,很容易发生某些状态被错误修改的情况。例如,将列表分配给变量时,如果需要创建列表的副本,则很容易忘记添加[:]

x = [0,1,2,3,4,5]
y = x    # oops, should have been x[:]
y[2] = 7 # now we modify state somewhere...
x
=> [0, 1, 7, 3, 4, 5]
至少更有可能识别此类问题的一种可能方法是以随机顺序执行单元测试。我根据https://stackoverflow.com/a/4006044/5747415中的想法运行了一个实验:

import unittest
import random
def randcmp(_, x, y):
    return random.randrange(-1, 2)
unittest.TestLoader.sortTestMethodsUsing = randcmp

结果是,测试的执行顺序在测试执行之间发生了变化。如果由于错误,您的测试碰巧有依赖项,那么您也许能够通过这种方式解决问题,因为某些执行顺序将导致失败。当然,您将从小规模开始(只执行少量测试),因此您有机会更容易地找到罪魁祸首。

也许值得一试...

951