QuickCheck for Python
Property-based testing for Python à la QuickCheck.
for_all takes a list of generators (see below) and a property. It then tests the property for arbitrary values of the generators.
Here’s an example testing the commutative and associative properties of ints:
for_all(int, int)(lambda a, b: a + b == b + a) for_all(int, int)(lambda a, b: a * b == b * a) for_all(int, int, int)(lambda a, b, c: c * (a + b) == a * c + b * c)
Note: These are not the same as Python generators. We should rename them. Generaters? Blech.
A generator is a specification of a set of possible Python objects. A generator is either:
arbitrary takes a generator and returns a single instance of the generator.
We provide a mixin with one classmethod, arbitrary, which raises NotImplementedError. To implement generators for your own classes, please inherit from ArbitraryInterface and provide an implementation for arbitrary.
Here’s an example implementation of a Binary Tree class:
class BinaryTree(ArbitraryInterface): ... @classmethod def arbitrary(cls): return arbitrary(one_of(Leaf, Node)) class Leaf(BinaryTree): ... @classmethod def arbitrary(cls): return cls(...) # an instance of Leaf. class Node(BinaryTree): ... @classmethod def arbitrary(cls): return cls( ... # This is equivalent: arbitrary(BinaryTree), # to this: BinaryTree.arbitrary() ) # an instance of Node with two subtrees.
We also provide an AbstractTestArbitraryInterface with you can mixin to your test cases for each class that implements ArbitraryInterface to ensure the arbitrary method is implemented:
class TestBinaryTree(AbstractTestArbitraryInterface, TestCase): def setUp(self): self.obj = BinaryTree