Frege and QuickCheck: Create properties

After going through the main parts of property base testing with QuickCheck and Frege now I’m focusing only in properties. Lets recall what was a property in the context of QuickCheck.

What is a property

A property is an executable specification meaning a function that holds for a set of values using the program (function or set of functions) you want to test.

Create a simple property

As a rule of thumb the easiest way of creating a property is to create a function that returns a Bool. A function retuning a Bool can be treated as a Testable value. Then use the Testable function as argument of the property function, to get a Property value and leave QuickCheck to do the rest. In summary:

  • Create a function that returns Bool

  • Invoke property passing the previous function

  • Invoke QuickCheck

Lets create a simple function. This function has certain properties:

  • Should double the absolute value of the number passed as argument if that number is greater than 0 and less or equals than 10

  • Otherwise returns 0

I’m using frege-gradle-plugin for these examples, actually I’m executing ./gradlew fregeQuickCheck --t which executes and waits until the source code changes to launch the tests again. Very useful while developing.

This is the specification we have to respect:

Specification
alwaysPositive :: Int -> Bool
alwaysPositive    x   = badImplementation x >= 0

alwaysPositiveCheck   = property (alwaysPositive)

Lets try a first version of our function:

Bad Implementation
badImplementation :: Int -> Int
badImplementation    x    = x * 2

And now execute QuickCheck to see if this first version holds:

Output
c.BasicsCheck.alwaysPositiveBadCheck: *** Failed!                                                                                                                                             (after 7 tests and 2 shrinks):
Falsifiable
-1

Error as expected. So just using a negative number as argument the function won’t hold. Ok, we should take the absolute number and then multiply by two.

Good Implementation
goodImplementation :: Int -> Int
goodImplementation    x
  | x >= 0 && x <= limit = x * 2
  | otherwise       = 0
  where limit = 10
Specification
alwaysPositive :: Int -> Bool
alwaysPositive    x   = goodImplementation x >= 0

alwaysPositiveCheck   = property (alwaysPositive)
Output
c.BasicsCheck.alwaysPositiveCheck: +++ OK, passed 100 tests

Perfect!! Ok this was a good warm up exercise, lets do something more complex.

Testable

If you check the property function type in the frege repl you’ll notice that it receives a value of type Testable and returns a Property. Bool defines an instance of Testable.

Checking property function type
frege> import Test.QuickCheck
...
frege> :t property
frege> Testable prop => prop -> Property