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}}:不要与其他测试并行运行此测试,此测试很特殊,需要完全隔离。
我的解决方法是在搜索配置文件的函数中添加一个可选参数。该参数仅由测试套件传递。它会忽略配置文件而不删除它。实际上删除测试文件更优雅,这就是我实际想要测试的内容。
答案 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
,因为我们在那时不需要任何一个。