进行永远不会并行运行的Python单元测试

时间:2014-02-14 08:03:31

标签: python unit-testing python-unittest

tl; dr - 我想编写一个Python unittest函数来删除文件,运行测试并恢复文件。这会导致竞争条件,因为unittest并行运行多个测试,并且删除和创建一个测试的文件会混淆同时发生的其他测试。

长具体示例:

我有一个名为converter.py的Python模块,它在test_converter.py中有相关的测试。如果在config_custom.csv所在的目录中存在名为converter.py的文件,则将使用自定义配置。如果没有自定义CSV配置文件,则converter.py内置了默认配置。

我使用Python 2.7标准库中的unittest编写了一个单元测试来验证此行为。 setUp()中的单元测试会将config_custom.csv重命名为wrong_name.csv,然后运行测试(希望使用默认配置),然后在tearDown()中将文件重命名为config_custom.csv应该是这样的。

问题: Python单元测试并行运行,我遇到了可怕的竞争条件。文件unittest将以非确定性方式在其他单元测试的中间重命名。它会在我运行整个测试套件的90%的时间内导致至少一个错误或失败。

理想的解决方案是告诉{{1}}:不要与其他测试并行运行此测试,此测试很特殊,需要完全隔离。

我的解决方法是在搜索配置文件的函数中添加一个可选参数。该参数仅由测试套件传递。它会忽略配置文件而不删除它。实际上删除测试文件更优雅,这就是我实际想要测试的内容。

4 个答案:

答案 0 :(得分:1)

我经常需要完全隔离地运行测试。我发现一致工作的唯一方法是将这些测试放在单独的类中。同意在测试中处理配置文件仍然有些痛苦。

对于我现在正在做的事情,我也可以尝试使用pytest-ordering之类的命令来以更加确定性的方式运行测试。

答案 1 :(得分:0)

首先,支持并行性的大多数测试框架也支持串行某些重要测试的方法。例如,Python Fabric支持串行注释(当您使用命令行标志-P启动测试作为并行套件时):

from fabric.api import *

def runs_in_parallel():
    pass

@serial
def runs_serially():
    pass

但是,我认为你不应该这样做,我认为你应该停下来蔑视片刻。在Single Responsibility Principal之后,这就是我要说的。

您处于这样一种情况:测试基本上已经确定了您的代码的条件,它突出了您的凝聚力。

你现在应该做的是意识到“converter.py”有太多的责任,不仅它在幕后执行一些复杂的操作,它还负责以一种方式管理它自己的创建和设置。可能太多了。

也许如果你有一个可以在该文件中管理读取的对象,那么你可以轻松地模拟/存根它并产生你想要测试的条件。

答案 2 :(得分:0)

最好的测试策略是确保您对不相交的数据集进行测试。这将绕过任何竞争条件并使代码更简单。如果您使用上下文管理器,我还会嘲笑open__enter__ / __exit__。这将允许您伪造文件不存在的事件。

答案 3 :(得分:-1)

问题是config_custom.csv的名称本身应该是一个可配置的参数。然后,每个测试都可以只查找config_custom_<nonce>.csv,并且可以并行运行任意数量的测试。

整个套件的清理可以清除config_custom_*.csv,因为我们在那时不需要任何一个。