Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Property-based testing with Clojure test.check

Reid Draper
December 17, 2014

Property-based testing with Clojure test.check

Traditional unit or example-based tests are a useful tool for developing confidence in correctness. Trouble is, they require linear effort to increase this confidence -- it takes twice as long to write eight tests as it does four. Furthermore, example-based tests are limited by their authors imagination.

Property-based testing takes a different approach: tests are written as properties that should hold true for an entire domain of randomly-generated input. The number of test-cases generated are limited only by your compute-resources and patience. In this talk, we'll take a look at the principles of property-based testing, as well as some pragmatic examples.

Reid Draper

December 17, 2014
Tweet

More Decks by Reid Draper

Other Decks in Programming

Transcript

  1. (= [5 2 1] (reverse [1 2 5])) (= [1

    2 3 4 5] (reverse [5 4 3 2 1])) (= [5] (reverse [5])) (= [] (reverse []))
  2. (= [5 2 1] (reverse [1 2 5])) (= [1

    2 3 4 5] (reverse [5 4 3 2 1])) (= [5] (reverse [5])) (= [] (reverse [])) (= [7 8 2 5] (reverse [5 2 8 7])) (= [55 54 53] (reverse [53 54 55])) (= [-15 15] (reverse [15 -15])) (= [true false] (reverse [false true]))
  3. {:3aBA "~e", ({"" false} \") ("r" "" {{} 0, :y

    {0 \+}}), [2 {} [[] {0 :v7}]] -1/4, (1 2 \') {}, :4 ["" ({0 true})], {false {}, {(0) (\^)} 0, ("m" [false]) ((true) {}), [[\t] ()] {}} -3}
  4. (concat a b) ;; Returns a lazy seq representing the

    concatenation of the elements in the supplied colls.
  5. (prop/for-all [a (gen/vector gen/any) b (gen/vector gen/any)] (= (count (concat

    a b)) (+ (count a) (count b)))) universal-quantification
  6. [[:disj -108] [:disj -24] [:disj 89] [:transient] [:conj 12] [:disj

    -136] [:transient] [:conj -145] [:conj -8] [:persistent!] [:persistent!] [:conj 25] [:conj 142] [:conj 146] [:persistent!] [:transient] [:conj 95] [:persistent!] [:disj -86] [:transient] [:persistent!] [:transient] [:persistent!] [:conj -109] [:transient] [:transient] [:persistent!] [:disj -6] [:transient] [:persistent!] [:conj -50] [:persistent!] [:conj -166] [:transient] [:conj 136] [:persistent!] [:persistent!] [:transient] [:disj 155] [:persistent!] [:transient] [:transient] [:disj 143] [:persistent!] [:persistent!] [:transient] [:conj -10] [:transient] [:conj -59] [:conj -34] [:transient] [:transient] [:disj 111] [:transient] [:disj -33] [:transient] [:conj -96] [:transient] [:disj 93] [:disj -130] [:conj 88] [:disj 14] [:transient] [:disj 9] [:persistent!] [:disj 86] [:conj 109] [:conj -45] [:persistent!] [:persistent!] [:disj -141] [:conj -14] [:persistent!] [:persistent!] [:conj -104] [:conj -83] [:persistent!] [:persistent!] [:conj -73] [:conj 13] [:persistent!] [:persistent!] [:persistent!] [:disj -14] [:conj -129] [:disj -53] [:transient] [:conj -110] [:conj 60] [:conj 11] [:disj -128] [:disj -42] [:disj 18] [:disj 73] [:disj 33] [:transient] [:persistent!] [:persistent!] [:transient] [:persistent!] [:transient] [:disj -123] [:disj -141] [:conj -26] [:conj -92] [:conj -116] [:conj 101] [:disj -133] [:conj 58] [:transient] [:disj -110] [:persistent!] [:disj 105] [:conj 26] [:conj -110] [:persistent!] [:transient] [:persistent!] [:persistent!] [:disj -5] [:conj 117] [:transient] [:persistent!] [:disj 96] [:persistent!] [:disj 52] [:persistent!] [:disj -132] [:transient] [:transient] [:conj -108] [:disj 121] [:persistent!]]
  7. any any-printable boolean byte bytes char char- alpha-numeric char-ascii hash-map

    int keyword list map nat neg-int pos-int ratio s-neg-int s-pos- int string string-alpha-numeric string-ascii tuple vector
  8. (gen/sample (gen/vector gen/int)) ([] [1] [2 0] [1 2 -1]

    [] [0] [-4] [] [-8] [4 0 2 -8 -9]) vector
  9. (last (gen/sample gen/any-printable)) {:3aBA "~e", ({"" false} \") ("r" ""

    {{} 0, :y {0 \+}}), [2 {} [[] {0 :v7}]] -1/4, (1 2 \') {}, :4 ["" ({0 true})], {false {}, {(0) (\^)} 0, ("m" [false]) ((true) {}), [[\t] ()] {}} -3} any
  10. (gen/sample (gen/elements [:clojure :haskell :erlang :python :ruby])) (:clojure :haskell :haskell

    :clojure :clojure :python :cloj ure :clojure :ruby :ruby) elements
  11. (gen/sample (gen/frequency [[5 (gen/return :weekday)] [2 (gen/return :weekend)]])) (:weekday :weekday

    :weekend :weekday :weekday :weekend :wee kend :weekend :weekday :weekday) frequency
  12. (gen/sample (gen/fmap odd? gen/int)) (false true false true true false

    false false false false) apply odd? to every generated value
  13. ([[0] 0] [[1 -2] 1] [[2 2] 2] [[-3 -3]

    -3] [[4 -4] -4] [[2 1] 2] [[-6 -6 -5 -1] -5] [[8 -5 6 -6 -6 -5 7 -7] 8] [[-3 2 -5 -4] -5] [[7 5] 5]) tuples of vector and chosen element