Skip to content

Commit 81fcefe

Browse files
more writing
1 parent af5086f commit 81fcefe

File tree

1 file changed

+17
-33
lines changed

1 file changed

+17
-33
lines changed

docs/Manual.md

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -333,55 +333,39 @@ We can do a better job by constraining the condition using `genFromSpec`
333333
spec1 :: Specification (Int,Int,Int,Int)
334334
spec1 = constrained' $ \ w x y z -> [w <. x, x <. y, y <. z]
335335

336-
prop2:: Gen Property
337-
prop2 = do
338-
(w,x,y,z) <- genFromSpec spec1
339-
pure $ (w < x && x < y && y < z) ==> property (w < z)
336+
prop2:: Property
337+
prop2 =
338+
forAll (genFromSpec spec1) $ \(w,x,y,z)
339+
(w < x && x < y && y < z) ==> property (w < z)
340340
```
341341

342-
Now the test passes.
342+
Now the test passes!
343343

344344
```
345345
ghci> quickCheck prop2
346346
+++ OK, passed 100 tests.
347347
```
348348

349-
Now this isn't a very good test either, since the precedent is alway true. A better solution would be to
350-
generate a mix, where the precedent is True most of the time, but sometimes False. Like this.
349+
The second interpretation of the specification is as a constraint checker, implemented as the function.
351350

352351
```haskell
353-
prop3:: Gen Property
354-
prop3 = do
355-
(w,x,y,z) <- frequency [(9,genFromSpec spec1),(1,arbitrary)]
356-
pure $ (w < x && x < y && y < z) ==> property (w < z)
357-
```
358-
359-
Observe the result:
360-
361-
```
362-
ghci> quickCheck prop3
363-
+++ OK, passed 100 tests; 7 discarded.
352+
conformsToSpec :: HasSpec a => a -> Specification a -> Bool
364353
```
365354

366-
The `7 discarded` arises because in most random samples of `w`, `x`, `y`, and `z`, the ordering constraint will
367-
not be true, so a discard will occur. Because the ratio of constrained to random is 9 to 1, so the number
368-
of failures is small enough that we don't `give up`. The role of the `arbitrary` is to guard against the possibility
369-
that the constrained spec might be over constrained, and in that case will be values that will never be chosen in a random test.
370-
Which means we will not be choosing a good sample of the test space, so some bugs might escape detection.
371-
By adjusting the test so that any `arbitrary` samples, that are not ordered, pass the test, we identify
372-
a piuntin the sample space that the code does not handle correctly. In a later section we discuss how to use
373-
QuickChrck `classify` and `cover` write better tests.
374-
375-
The purpose of constrained generators is to make it possible to write conditional 'implication' properties
376-
that have a high probability of not being vacuously true, and to combine this with other random
377-
techniques to make better samples of the test-space.
378-
379-
The second interpretation of the specification is as a constraint checker, implemented as the function.
355+
Using this we can write a (admittedly silly) test that showcases this explicitly:
380356

381357
```haskell
382-
conformsToSpec :: HasSpec a => a -> Specification a -> Bool
358+
spec1 :: Specification (Int,Int,Int,Int)
359+
spec1 = constrained' $ \ w x y z -> [w <. x, x <. y, y <. z]
360+
361+
prop2' :: Property
362+
prop2' =
363+
forAll (genFromSpec spec1) $ \(w,x,y,z)
364+
(w,x,y,z) `conformsToSpec` spec1 ==> property (w < z)
383365
```
384366

367+
Which similarly will always succeed and should never be discarded.
368+
385369
## How we solve the constraints
386370

387371
Before we continue delving into how we use the library and the finer points

0 commit comments

Comments
 (0)