QuickCheck turns a testing requirement into a property and checks that property against automatically generated inputs. It suits small, pure algorithms whose input space is too broad for hand-written cases. A failing run produces a counterexample, and shrinking aims to reduce that failure to a minimal case. section 15.1.2
Testing a square property
The property x * x == square x checks a whole class of Integer values rather than a few expected results. QuickCheck commonly tries values near zero and type-range edges, so a malformed implementation can fail quickly when it mishandles ordinary inputs. section 15.1.2
spec :: Spec spec = prop "square" $ #1 \x -> (malformedSquare x == x * x) #2 -- Test output: > Falsified (after 2 tests): 1
Inspect the compact Hspec property and its falsification output, then compare it with the malformed implementation that passes after hiding a defect beyond the generated range. section 15.1.2
Use QuickCheck effectively by matching generation and execution to the system under test:
- Increase the accepted run count with withMaxSuccess when more generated cases are useful, while recognizing that finite testing cannot cover every Integer. section 15.1.2
- Run IO-based properties with monadicIO and run, including scenarios executed through real interpreters and a prepared runtime. section 15.1.3
- Generate arbitrary parameters with pick arbitrary, then use pre to discard values outside the generator’s valid bounds. section 15.1.3
Listing 15.5 Adjusting the test data generator
...
$ monadicIO $ do
x :: Int <- pick arbitrary #1
y :: Int <- pick arbitrary
pre (x >= 4 && x <= 10 && y >= 4 && y <= 10) #2
let action = generateLabyrinth (x, y) 3 3 #3
eLab <- run (try (runLangL coreRuntime action)) #4
case eLab of #5
Left (err :: SomeException) -> assert False
Right lab -> do
let (x, y) = getBounds lab
assert (x * y >= 16 && x * y <= 100)
Follow the constrained generator example: choose dimensions, reject invalid values, run the interpreted action, and assert the resulting labyrinth bounds. section 15.1.3


