Slide 1

Slide 1 text

clojure.test.check Reid Draper @reiddraper

Slide 2

Slide 2 text

testing

Slide 3

Slide 3 text

performance

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

test.check

Slide 10

Slide 10 text

github.com/clojure/ test.check

Slide 11

Slide 11 text

previously called simple-check

Slide 12

Slide 12 text

let's see an example

Slide 13

Slide 13 text

(-> #{} (conj 109) (conj -110)! transient (disj! -110)! persistent! (conj -110))!

Slide 14

Slide 14 text

(-> #{} (conj 109) (conj -110)! transient (disj! -110)! persistent! (conj -110))!

Slide 15

Slide 15 text

(def transient-property! (prop/for-all! [a (gen/vector gen-action)]! (= (apply-actions #{} a)! (apply-actions #{} (filter-actions a)))))!

Slide 16

Slide 16 text

(tc/quick-check! 1e5 ;; 100,000! transient-property)!

Slide 17

Slide 17 text

{:result false,! :failing-size 92,! :num-tests 2893,! :fail "...",! :shrunk! {:total-nodes-visited 440! :depth 83! :result false! :smallest "..."}}!

Slide 18

Slide 18 text

[[:conj 109] [:conj -110] [:transient ]! [:disj -110] [:persistent!] [:conj -110]]!

Slide 19

Slide 19 text

CLJ-1285

Slide 20

Slide 20 text

fixed in clojure 1.6

Slide 21

Slide 21 text

github.com/reiddraper/ clojure-transient-test

Slide 22

Slide 22 text

clojure clojurescript pedestal core.matrix collection-check byte-streams

Slide 23

Slide 23 text

quickcheck Haskell (QuickCheck) 2000 Erlang (EQC) 2006 Scala (ScalaCheck) ~2008

Slide 24

Slide 24 text

property-based testing generative-testing random-testing

Slide 25

Slide 25 text

(prop/for-all! [a (gen/vector gen/any)! b (gen/vector gen/any)]! (= (count (concat a b))! (+ (count a) (count b))))!

Slide 26

Slide 26 text

(prop/for-all! [a (gen/vector gen/any)! b (gen/vector gen/any)]! (= (count (concat a b))! (+ (count a) (count b))))! universal-quantification

Slide 27

Slide 27 text

(prop/for-all! [a (gen/vector gen/any)! b (gen/vector gen/any)]! (= (count (concat a b))! (+ (count a) (count b))))! binding

Slide 28

Slide 28 text

(prop/for-all! [a (gen/vector gen/any)! b (gen/vector gen/any)]! (= (count (concat a b))! (+ (count a) (count b))))! property

Slide 29

Slide 29 text

;; `p` is the aforementioned code! (tc/quick-check 100 p)! ;; => {:result true, :num-tests ! 100, :seed 1395110930836}!

Slide 30

Slide 30 text

thinking in properties

Slide 31

Slide 31 text

roundtrip trusted-implementation input/output relation

Slide 32

Slide 32 text

roundtrip

Slide 33

Slide 33 text

(prop/for-all! [a gen/any-printable]! (= a (-> a prn-str! edn/read-string)))! serialize de-serialize

Slide 34

Slide 34 text

trusted-implementation

Slide 35

Slide 35 text

(def transient-property! (prop/for-all! [a (gen/vector gen-action)]! (= (apply-actions #{} a)! (apply-actions #{} (filter-actions a)))))!

Slide 36

Slide 36 text

input/output relation

Slide 37

Slide 37 text

(prop/for-all! [a (gen/vector gen/any)! b (gen/vector gen/any)]! (= (count (concat a b))! (+ (count a) (count b))))!

Slide 38

Slide 38 text

generators

Slide 39

Slide 39 text

(prop/for-all! [a (gen/vector gen/any)! b (gen/vector gen/any)]! (= (count (concat a b))! (+ (count a) (count b))))! generators

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

(gen/sample gen/boolean)! (false false false false false true false false true true)! ! boolean

Slide 42

Slide 42 text

(gen/sample gen/int)! (0 0 -2 -3 1 3 -2 0 0 -9)! int

Slide 43

Slide 43 text

(gen/sample (gen/vector gen/int))! ([] [1] [2 0] [1 2 -1] [] [0] [-4] [] [-8] [4 0 2 -8 -9])! ! vector

Slide 44

Slide 44 text

(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

Slide 45

Slide 45 text

bind choose elements frequency no-shrink not- empty resize return sample sample-seq shrink-2 sized such-that

Slide 46

Slide 46 text

(gen/sample (gen/return :foo))! (:foo :foo :foo :foo :foo :foo :foo ! :foo :foo :foo)! return

Slide 47

Slide 47 text

(gen/sample (gen/choose 5 10))! (7 8 9 6 6 5 8 9 10 10)! choose

Slide 48

Slide 48 text

(gen/sample (gen/elements ! [:clojure :haskell :erlang :python :ruby]))! ! (:clojure :haskell :haskell :clojure :clojure :python :c lojure :clojure :ruby :ruby)! elements

Slide 49

Slide 49 text

(gen/sample (gen/one-of [gen/boolean gen/byte]))! ! (119 true -24 120 -93 true false 27 false false)! one-of

Slide 50

Slide 50 text

(gen/sample (gen/frequency ! [[5 (gen/return :weekday)]! [2 (gen/return :weekend)]]))! ! (:weekday :weekday :weekend :weekday :weekday :weekend : weekend :weekend :weekday :weekday)! frequency

Slide 51

Slide 51 text

(gen/sample (gen/such-that #(not= 0 %) gen/int))! (-1 -2 -1 2 3 -5 -6 6 -5 -1)! ! ! ! ! such-that

Slide 52

Slide 52 text

(gen/sample (gen/fmap odd? gen/int))! (false true false true true false false false false false)! ! fmap

Slide 53

Slide 53 text

(gen/sample (gen/fmap odd? gen/int))! (false true false true true false false false false false)! ! apply odd? to every generated value

Slide 54

Slide 54 text

(gen/sample (gen/bind! (gen/not-empty (gen/vector gen/int))! #(gen/tuple (gen/return %) (gen/elements %))))! ! ! ! bind

Slide 55

Slide 55 text

([[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

Slide 56

Slide 56 text

shrinking

Slide 57

Slide 57 text

remember the counterexample before….

Slide 58

Slide 58 text

[[:conj 109] [:conj -110] [:transient ]! [:disj -110] [:persistent!] [:conj -110]]!

Slide 59

Slide 59 text

[[: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!]]!

Slide 60

Slide 60 text

[[:conj 109] [:conj -110] [:transient ]! [:disj -110] [:persistent!] [:conj -110]]!

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

(defspec! first-element-is-min! 100 ;; num iterations! (prop/for-all! [a gen/int]! …))

Slide 63

Slide 63 text

github.com/cemerick/ double-check cljs compatible fork

Slide 64

Slide 64 text

concurrency testing

Slide 65

Slide 65 text

concurrent programs are hard to test

Slide 66

Slide 66 text

why are concurrent programs hard to test?

Slide 67

Slide 67 text

their execution is non- deterministic

Slide 68

Slide 68 text

let's make it deterministic

Slide 69

Slide 69 text

based on PULSE

Slide 70

Slide 70 text

for all thread interleavings…

Slide 71

Slide 71 text

(sched/shedule! (let [p (promise)]! (future (deliver p true))! (future (Thread/sleep 1000) (deliver p false))! (= true @p)))!

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

github.com/clojure/ test.check github.com/reiddraper/ clojure-transient-test