繁体   English   中英

测试python函数的非确定性行为

[英]Testing for non-deterministic behavior of python function

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

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

有没有办法编写自动化测试来捕获这种bug?

也许有一种方法来破解python的dict,以便迭代器在这个测试中是随机的而不是随意的? 那样重复调用函数会更容易发生分歧吗? 这似乎是一个相当复杂的方法,但我想不出任何其他方式。

编辑:

我们目前正在使用Python 2.7。

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

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

如果要随机化散列种子,可以将-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中的默认行为。

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

使用这些作为代码的输入而不是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 ,因此对输入进行操作是不够的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM