Skip to content

Generative testing with for all

Phillip Mates edited this page Nov 21, 2017 · 5 revisions

Generative testing is a very useful and quick way to test code behavior.

clojure.test.check provides great generative testing tools that can be used with Midje:

(require
  '[clojure.test.check :as tc]
  '[clojure.test.check.properties :as prop]
  '[clojure.test.check.generators :as gen])
(use 'midje.repl)

(tc/quick-check
  10
  (prop/for-all*
    [gen/s-pos-int gen/int]
    (fn [positive-num int]
      (fact (+ positive-num int) => pos?))))

This unfortunately requires importing several namespaces, making specific api calls, and doesn't show failure messages for shrunken data.

So to make it easier to write generative tests in Midje, the for-all form was included as of 1.9.0-alpha11:

(require '[clojure.test.check.generators :as gen])
(use 'midje.repl)
(require '[midje.experimental :refer [for-all]])
(for-all
  [positive-num gen/s-pos-int
   int          gen/int]
  (fact "An integer added to a positive number is always a number?"
    (+ positive-num int) => integer?)
  (fact "An integer added to a positive number is always positive?"
    (+ positive-num int) => pos?))
FAIL "An integer added to a positive number is always positive?" at (example.clj:6)
Actual result did not agree with the checking function.
Actual result:
0
Checking function: pos?

quick-check seed:
1510234310986

quick-check shrunken failing values:
{int -1 positive-num 1}

The for-all form has three parts: the symbol for-all (and optional description and options map), the binding vector where symbols are bound to example values generated from the generators, and the body, which should contain one or more fact expressions.

quick-check options

The number of runs, size of generated values, and the randomness seed can be configured within for-all by passing in an optional configuration map with the keys :num-tests, :max-size, and :seed:

(defn my-keys [a-map] (map second a-map))
(for-all 
  [str-map (gen/map gen/keyword gen/string)]
  {:max-size 10
   :num-tests 15
   :seed 1510160943861}
  (fact "extracted keys are strings"
    (my-keys str-map) => (has every? string?))
  (fact "my-keys matches keys behavior"
    (my-keys str-map) => (keys str-map)))
Clone this wiki locally