4

我们有一个需要确定性的大而复杂的函数。它是我们公司的主力之一,涵盖了大量的代码。由于 python 的 dict 迭代器,此代码通常变得不确定。这种情况发生了很多次,很难追查到,而且往往不会立即注意到。我们想编写一个自动化测试来检测非确定性,但我不知道该怎么做。

我们尝试在循环中运行该函数,并且测试结果始终相同,但有时,即使该函数是非确定性的,由于 dict 迭代器的任意但有些一致的顺序,该函数也会通​​过此测试。

有没有办法编写一个自动化测试来捕捉这种错误?

也许有一种方法可以破解 python 的 dict 以便在此测试期间迭代器是随机的而不是任意的?这样重复调用函数就更有可能发散?这似乎是一个相当复杂的方法,但我想不出任何其他方法。

编辑:

我们目前使用的是 Python 2.7。

我们对各种子模块进行了单元测试,但是由于 dict 顺序的任意但一致的性质,它们通常不会暴露不确定性。

此外,也许非确定性不是描述这个问题的正确方法。这个函数需要 {id : data},但是 ids 的值不应该影响代码的结果,但是由于 python dict 排序,它有时会。也许最好的测试方法是用随机值替换 id 并检查在多次运行不同 id 后输出是否相同。

4

2 回答 2

6

如果要随机化哈希种子,可以将-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

啦啦

~$ 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 中的默认行为。

于 2014-02-20T20:57:41.700 回答
0

您可以使用OrderedDict强制两个相似dict的 s 具有不同的“顺序”。

使用这些作为代码而不是 vanilladict的输入,您可以可靠地检查代码行为与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

但是,这可能更适合对小功能进行单元测试。如果您同时测试一个“大而复杂的函数”,那么dicts 很可能是在函数内部生成的,因此对输入进行操作是不够的。

于 2016-10-21T21:31:25.737 回答