我们有一个庞大而复杂的功能,需要具有确定性。它是我们公司的主力之一,涵盖了大量的代码。由于python的dict迭代器,这段代码经常变得不确定。这已经发生了很多次,并且很难追踪,并且通常不会立即注意到。我们想编写一个自动测试来检测非确定性,但我不知道该怎么做。
我们已经尝试在循环中运行该函数,并且测试结果总是相同的,但有时,即使函数是非确定性的,该函数也会通过此测试,因为该函数的任意但有些一致的顺序dict iterator。
有没有办法编写自动化测试来捕获这种错误?
也许有一种方法可以破解python的dict,以便迭代器在这个测试中是随机的而不是随意的?那样重复调用函数会更容易发生分歧吗?这似乎是一个相当复杂的方法,但我想不出任何其他方式。
编辑:
我们目前正在使用Python 2.7。
我们对各个子模块进行了单元测试,但是由于字典顺序的任意但一致的性质,它们通常不会暴露非确定性。
另外,也许非确定性不是描述这个问题的正确方法。这个函数接受{id:data},但是id的值不应该影响代码的结果,但是由于python dict的排序,它有时会这样做。也许测试这个的最好方法是用随机值替换id,并检查多次运行不同id后输出是否相同。
答案 0 :(得分:5)
如果要随机化散列种子,可以将-R
标志指定为python:
-R : use a pseudo-random salt to make hash() values of various types be
unpredictable between separate invocations of the interpreter, as
a defense against denial-of-service attacks
a la
~$ python -c "print {y:x for x,y in enumerate('foobar')}"
{'a': 4, 'r': 5, 'b': 3, 'o': 2, 'f': 0} #it will always be this
~$ python -R -c "print {y:x for x,y in enumerate('foobar')}"
{'a': 4, 'b': 3, 'r': 5, 'f': 0, 'o': 2}
~$ python -R -c "print {y:x for x,y in enumerate('foobar')}"
{'a': 4, 'b': 3, 'r': 5, 'o': 2, 'f': 0}
~$ python -R -c "print {y:x for x,y in enumerate('foobar')}"
{'f': 0, 'o': 2, 'b': 3, 'r': 5, 'a': 4}
~$ python -R -c "print {y:x for x,y in enumerate('foobar')}"
{'r': 5, 'f': 0, 'o': 2, 'a': 4, 'b': 3}
请注意,此行为是python 3.3中的默认行为。
答案 1 :(得分:0)
您可以使用OrderedDict
强制两个类似的dict
s具有不同的"顺序"。
使用这些作为代码的输入而非vanilla dict
,您可以可靠地检查与dict
订单问题相关的代码行为。
例如,此测试有时会失败(相对很少):
d1 = {'a':1, 'b': 2}
d2 = dict(d1)
j1 = json.dumps(d1)
j2 = json.dumps(d2)
assert j1 == j2:
并且此测试无法预测:
import json
from collections import OrderedDict
d1 = OrderedDict([('a', 1), ('b', 2)])
d2 = OrderedDict([('b', 2), ('a', 1)])
j1 = json.dumps(d1)
j2 = json.dumps(d2)
assert j1 == j2
但是,这可能更适合单元测试小功能。如果你正在测试一个大而复杂的功能"同时,很可能dict
s在函数内生成,因此对输入的作用不够。