Usage

Property checking

To start using pyquchk you just need to import for_all():

>>> from pyquchk import for_all

Using for_all() pyquchk tests whether a property holds for all parameters.

For a property to hold, the function tested should return a value equivalent to True and raise no exceptions:

>>> for_all(lambda x: True, x=int).passed
True
>>> for_all(lambda x: False, x=int).passed
False
>>> for_all(lambda x: 1/0, x=int).passed
False

The actual data which caused a property to fail is also available. Although exact values are not guaranteed to stay the same each run, the property always fails for this data:

>>> p = lambda x, y: x <= y
>>> data = for_all(p, x=int, y=int).data
>>> assert not p(data['x'], data['y'])

For other result metadata available, see Result fields.

If default parameters don’t fit your needs, it’s easy to specify any custom ones. At first, you need to import the Arbitrary classes you want to use:

>>> from pyquchk.arbitraries import int_, list_

These classes without any parameters are equivalent to specifying just int or list correspondingly:

>>> for_all(lambda x: 0 <= x <= 10, x=int_).passed
False
>>> for_all(lambda xs: sum(xs) < 2**20, xs=list_).passed
False

However, you can tweak the parameters, and now the same properties hold for all values:

>>> for_all(lambda x: 0 <= x <= 10, x=int_(0, 10)).passed
True
>>> xs = list_(length=int_(0, 10), elements=int_(-100, 100))
>>> for_all(lambda xs: sum(xs) < 2**20, xs=xs).passed
True

Writing and running tests

A trivial function example

Suppose you have a function that sums up two given numbers:

>>> def add(a, b):
...     return a + b

and want to test it. Usually tests are written like this:

>>> def test_add():
...     assert add(1, 1) == 2
...     assert add(1, 2) == 3
...     assert add(2, 2) == 4
...     assert add(2, -10) == -8
>>> test_add()

i.e. the author states explicitly what result the function should have for different arguments. However, this isn’t convenient at all, and highly depends on the coverage given. For example, the test written before runs successfully for this definition of add:

>>> def add(a, b):
...     return abs(a) + b
>>> test_add()

A better way to write tests is to use this framework, pyquchk. The test will look like this:

>>> from pyquchk import qc
>>> @qc
... def test_add(a=int, b=int):
...     assert add(a, b) == a + b

This passes for the correct definition of add:

>>> def add(a, b):
...     return a + b
>>> test_add()

And doesn’t for the wrong one:

>>> def add(a, b):
...     return abs(a) + b
>>> test_add()
Traceback (most recent call last):
    ...
pyquchk.checker.CheckError: test failed due to AssertionError
Failure encountered for data:
  a = ...
  b = ...

So, as you see even from this trivial example, there is much better coverage with less code. Also, this way the programmer has to think better about what properties should always hold for the function and formulate them. Such properties can even be used to complement the function documentation.

The Python source file with tests written this way can be used as any other test file, when running with nosetests for example.

A function and its reverse

Testing two functions, one of which is the reverse for the other:

>>> def mul2(x):
...     return x * 2
>>> def div2(x):
...     return x // 2
>>> @qc
... def test_muldiv(x=int):
...     assert div2(mul2(x)) == x
>>> test_muldiv()

However, the opposite order doesn’t always results in the same value:

>>> @qc
... def test_divmul(x=int):
...     assert mul2(div2(x)) == x
>>> test_divmul()
Traceback (most recent call last):
    ...
pyquchk.checker.CheckError: test failed due to AssertionError
Failure encountered for data:
  x = 1

But with floating-point division this passes too:

>>> def div2(x):
...     return x / 2.0
>>> test_divmul()

Checking some property of the result

The techniques from the previous two examples aren’t always possible to implement or it can require writing a large function for tests only. Here I will show a way which allows testing for almost any function - checking a property of the result.

A very simple example of this can be the sum of positive integers, which should be greater than any of its arguments:

>>> def add(a, b):
...     return a + b
>>> @qc
... def test_add(a=int_(low=1), b=int_(low=1)):
...     assert add(a, b) > a
...     assert add(a, b) > b
>>> test_add()

Project Versions

Table Of Contents

Previous topic

pyquchk - random and serial testing

Next topic

Features

This Page