用于unittest的智能随机生成状态持久性
UnittestRandGenState的Python项目详细描述
简介
随机单元测试很好。在执行过程中,输入到算法的数据不一致,因此每次测试成功运行时,您对算法的信心都会增加。不幸的是,当测试失败时,这种不一致性使得在问题解决之前很难复制输入。
这个库提供了一个简单的元类,用于放入解决这个问题的unittest.TestCase。只要一个测试失败,它将继续在每次执行时做出相同的随机选择(通过random或numpy.random)。任何通过前一次执行的测试,都将得到一组新的随机选择。
示例
考虑下面一个测试用例的简化示例,其中有三个函数测试一些算法。第一个和第三个算法是可以的,但是第二个算法在给定一个除以20的数字时有一个错误(简化的示例直接断言这一点)。
import random class TestMyAlgs(unittest.TestCase): # This "algorithm" is OK. def test_ok(self): i = random.randint(100, 200) self.assertLess(i, i + 1) # This "algorithm" fails for inputs that divide by 20. def test_bad(self): i = random.randint(100, 200) self.assertNotEqual(i % 20, 0, i) # This "algorithm" is OK too. def test_another_ok(self): i = random.randint(100, 200) self.assertLess(i - 1, i)
第二个函数将失败约5%的执行。当它这样做时,可能很难(特别是在现实生活中)重现问题,并最终解决它。
使用这个库,一个简单的更改会使事情变得更容易。简单使用 unittest_rand_gen_state.Saver作为元类:
import random import unittest_rand_gen_state class TestMyAlgs(unittest.TestCase, metaclass = unittest_rand_gen_state.Saver): ...
或者,使用较旧的python版本:
import random import unittest_rand_gen_state class TestMyAlgs(unittest.TestCase): __metaclass__ = unittest_rand_gen_state.Saver ...
没有什么需要改变的。
一旦TestMyAlgs.test_bad在某些执行中首先失败,那么它在随后的执行中将始终失败。也就是说,如果第一次失败时使用
====================================================================== FAIL: test_bad (__main__.TestMyAlgs) ---------------------------------------------------------------------- Traceback (most recent call last): File "/usr/local/lib/python2.7/dist-packages/unittest_rand_gen_state/__init__.py", line 75, in wrapped fn(*args, **kwargs) File "__init__.py", line 21, in test_bad self.assertNotEqual(i % 20, 0, i) AssertionError: 140 ----------------------------------------------------------------------
接下来的每一次执行都将以完全相同的方式失败,直到它被修复。
同时,另外两个测试将一直重新运行。
下载、安装和错误跟踪
包裹在PyPI处。
通常使用python库的设置。类型:
^{tt3}$
or
^{tt4}$
错误跟踪在Google Code上。
延伸
这个库提供的元类处理random和numpy.random的状态,这应该足以进行几乎所有的测试。但是,可以通过将库作为元类(提供三个类方法的unittest_rand_gen_state.Saver的子类)删除来扩展库:
- ^{tt6}$: A method specifying the meaning of resetting the random-generation state (e.g., ^{tt7}$)
- ^{tt8}$: A method specifying the query to call for getting the current random-generation state (e.g., ^{tt9}$)
- ^{tt10}$: A method specifying the function to call to restore the random-generation state using the value returned by ^{tt8}$ (e.g., ^{tt12}$)
例如,假设一个随机生成库,groovy_rng具有函数groovy_rng.seed(将状态设置为由当前时间确定的某个函数)、groovy_rng.get_state,返回一个int,以及groovy_rng.set_state获取一个int,那么这里有一个用于处理groovy_rng的元类:
class GroovyRNGSaver(unittest_rand_gen_state.Saver): reset_state = groovy_rng.seed get_state = groovy_rng.get_state set_state = groovy_rng.set_state
这个元类可以像前面的例子一样使用。
更改
Version | Date | Description |
---|---|---|
0.1.4. | 15/03/2013 | Duplicate class-name bugfix, Python 2/3 coexistance bugfix |
0.1.3 | 23/02/2013 | Better test hashes, better support for extension |
0.1.2 | 22/02/2013 | Doc bugfix |
0.1.1 | 20/02/2013 | Less stateful design |
0.1.0 | 18/02/2013 | Initial Release |