When you write unit tests, it’s hard to find the right test cases. You want to be certain that you covered all the interesting cases, but you could simply not know or forget one of them. For example, if you unit test a function which receives an integer, you might think about testing 0, 1, and 2. But did you think about negative numbers? What about big numbers?

We were just thinking about a testing strategy for integers. A strategy is a generator of data. The property testing framework hypothesis offers a lot of strategies for many types. You can install it with pip install hypothesis .

One thing we can do with those inputs — those tests strategies — is to check if the runtime is acceptable and if the tested function/method does not crash.

It would be better if we compare the output of our function against something. A check for equality is likely not possible, so we need to know a property of our function. An invariant which we always expect to hold. We need to base our test on an inherent property of the function.

To whet your appetite for property-based testing even more:

Example: Integer factorization

We have a function factorize(n : int) -> List[int] which takes an integer and returns the prime factors:

An integer n is called a prime number if it is positive and divisible by exactly two numbers: 1 and n.

We want that the product of returned integers is the number itself. So this is how we design the functions behavior:

  • factorize(0) = [0] — an exception would have been reasonable as well
  • factorize(1) = [1] — strictly speaking, 1 is not a prime.
  • factorize(-1) = [-1] — … and neither is -1
  • factorize(-n) = [-1] + factorize(n) for n > 1

An implementation might look like this:

from typing import List
	import math

	def factorize(number: int) -> List[int]:
	    if number in [-1, 0, 1]:
	        return [number]
	    if number < 0:
	        return [-1] + factorize(-number)
	    factors = []

	    ## Treat the factor 2 on its own
	    while number % 2 == 0:
	        factors.append(2)
	        number = number // 2
	    if number == 1:
	        return factors

	    ## Now we only need to check uneven numbers
	    ## up to the square root of the number
	    i = 3
	    while i <= int(math.ceil(number ** 0.5)) + 1:
	        while number % i == 0:
	            factors.append(i)
	            number = number // i
	        i += 2
	    return factors

You might feel a bit uneasy about the condition in

while i <= int(math.ceil(number ** 0.5)) + 1:

#machine-learning #python #data-science #software-engineering #programming

Property-Based Testing with Python
1.10 GEEK