Quickcheck
This manual provides documentation for a Racket implementation of Quickcheck, a library that tests the specification of a program with randomly generated test inputs.
The original Quickcheck is a library for Haskell.
(require quickcheck) | package: quickcheck |
1 Quickstart
1.1 Installation
If you have not installed the package yet, run the following command from the command-line:
raco pkg install quickcheck
Note that this package will require Racket v6.0 or newer to install.
Alternatively, you may use the GUI package manager from DrRacket to install the package.
1.2 Running tests
To use Quickcheck, you first write a specification for a program as a property in ordinary Racket code. For example, the following is a property that expresses the English specification “the string->number function produces numbers when given strings”:
> (define string->number-returns-number (property ([str arbitrary-string]) (number? (string->number str))))
Given such a property, we can run random tests using quickcheck:
> (quickcheck string->number-returns-number)
Falsifiable, after 0 tests:
str = "\u0002\u0003\u0002"
You may have already guessed that this property will be easily falsified, since most strings do not actually parse as numbers.
Next, let’s write a property that we expect will actually succeed. For example, the following encodes the English specification “given two lists of integers, the result of appending them will have the same length as the sum of the original list lengths”:
> (define append-and-length-agree (property ([lst-1 (arbitrary-list arbitrary-integer)] [lst-2 (arbitrary-list arbitrary-integer)]) (= (+ (length lst-1) (length lst-2)) (length (append lst-1 lst-2)))))
Testing the property reveals that it holds up:
> (quickcheck append-and-length-agree) OK, passed 100 tests.
2 Running checks
procedure
(quickcheck prop) → void?
prop : testable?
Prints the result of the check, including a counterexample for the property if one was found.
Example: | ||||||
|
an integer representing the number of tests run,
a list of ...,
either #t if the tests were successful, #f if the arguments were exhausted, or an instance of the result structure type on a test failure.
Examples: | ||||||||||||
|
Prints the result of the check, including a counterexample for the property if one was found.
procedure
(check-results config prop) → result?
config : config? prop : testable?
3 Configuration, results, and utilities
struct
(struct config (max-test max-fail size print-every) #:extra-constructor-name make-config) max-test : number? max-fail : number? size : (-> integer? integer?) print-every : (-> integer? (listof any/c) any)
The max-test field represents the maximum number of succeeding tests that will be run. The max-fail field represents the maximum number of tests that can be run with no result before the checker terminates.
The size field should be a function of one argument that produces the test size given the current test number. The print-every field should be a function that takes the test number and the generated arguments and is called for its side effect.
struct
(struct result (ok stamp argument-list) #:extra-constructor-name make-result) ok : (or/c null #t #f) stamp : (listof string?) argument-list : (listof any/c)
The stamp field represents the labels that were relevant to this test execution. The argument-list is a list of the values generated for checking this test case.
syntax
(property ([id gen/arb-expr] ...) body0 body ...)
gen/arb-expr : (or/c arbitrary? generator?)
The ids are bound to the result of the given gen/arb-exprs inside the body expressions. The body expressions are used as the bodies of a predicate function that will be run with newly generated values from the specified generators or arbitraries.
Example: | ||||
|
Values that can be tested are the following:
boolean values (#t and #f),
instances of the result structure type,
instances of the property structure type,
or instances of the generator structure type.
4 Generators
struct
(struct generator (proc) #:extra-constructor-name make-generator) proc : (-> integer? random-generator? any/c)
The proc value should be a function that accepts an integer representing the size of the value, a random number generator, and returns a value for testing.
procedure
(choose-integer lower upper) → generator?
lower : integer? upper : integer?
procedure
(choose-real lower upper) → generator?
lower : real? upper : real?
value
value
procedure
(choose-char lower upper) → generator?
lower : char? upper : char?
procedure
(choose-list elem-gen size) → generator?
elem-gen : generator? size : integer?
procedure
(choose-vector elem-gen size) → generator?
elem-gen : generator? size : integer?
procedure
(choose-string char-gen size) → generator?
char-gen : generator? size : integer?
procedure
(choose-symbol char-gen size) → generator?
char-gen : generator? size : integer?
procedure
(choose-one-of opts) → generator?
opts : (listof any/c)
procedure
(choose-mixed promises) → generator?
promises : (listof (promise/c generator?))
procedure
(choose-with-frequencies freqs) → generator?
freqs : (listof (cons/c integer? generator?))
procedure
(generator-unit val) → generator?
val : any/c
procedure
(generator-bind gen k) → generator?
gen : generator? k : (-> any/c generator?)
procedure
(generator-sequence gens) → generator?
gens : (listof generator?)
procedure
(sized f) → generator?
f : (-> integer? generator?)
struct
(struct arbitrary (gen trans) #:extra-constructor-name make-arbitrary) gen : generator? trans : (-> any/c generator? generator?)
value
value
value
value
value
value
value
procedure
(arbitrary-mixed pred+promises) → arbitrary?
pred+promises : (listof (cons/c (-> any/c any/c) (promise/c arbitrary?)))
procedure
(arbitrary-one-of eql? vals) → arbitrary?
eql? : (any/c any/c -> any/c) vals : (listof any/c)
procedure
(arbitrary-pair fst rst) → arbitrary?
fst : arbitrary? rst : arbitrary?
procedure
(arbitrary-list elem) → arbitrary?
elem : arbitrary?
procedure
(arbitrary-vector elem) → arbitrary?
elem : arbitrary?
procedure
(arbitrary-tuple elem ...) → arbitrary?
elem : arbitrary?
procedure
(arbitrary-record constructor accessors elem ...) → arbitrary? constructor : procedure? accessors : (listof procedure?) elem : arbitrary?
value
value
value
procedure
(arbitrary-procedure result arg ...) → arbitrary?
result : arbitrary? arg : arbitrary?
5 Operations on properties
syntax
(==> bool-expr prop)
If bool-expr is #t, equivalent to prop. Otherwise, produces a property that returns no result.
procedure
(label str test) → generator?
str : string? test : testable?
syntax
(classify really? label-expr testable-expr)
syntax
(trivial really? testable-expr)
procedure
(collect lbl test) → generator?
lbl : any/c test : testable?
6 Random number generation
procedure
(random-generator-next rand) →
integer? random-generator? rand : random-generator?
procedure
→
random-generator? random-generator? rand : random-generator?
procedure
(random-integer rg low high) → integer?
rg : random-generator? low : integer? high : integer?