(str (js/Date.))
Open this presentation in your computer for a collaborative live coding session: http://slides.klipse.tech/clojure-spec-cr17/part1.html#slide-3
(It works also on mobile)
The interactive code snippets are powered by KLIPSE. 🤗
(map inc [1 2 3])
For the upcoming parts, we need to require two additional namespaces
(ns my.playground
(:require [clojure.test.check :as tc ]
[clojure.test.check.generators]
[clojure.test.check.properties :as prop :include-macros true]
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]
[clojure.spec.gen.alpha :as gen]))
We can generate data samples out of our specs:
(s/def ::big-integer (s/and integer?
#(> % 1000000)))
(s/def ::short-string (s/and string?
#(< (count %) 5)))
(s/def ::big-integer-or-short-string (s/or :int ::big-integer
:str ::short-string))
Either with gen/sample
:
(gen/sample (s/gen ::big-integer) 5)
Or with s/exercise
:
(s/exercise ::big-integer-or-short-string 5)
Why do we need to specify optional keys in a map?
(gen/sample (s/gen (s/keys :req [::big-integer])) 5)
(gen/sample (s/gen (s/keys :req [::big-integer] :opt [::short-string])) 5)
You can describe the shape of the args and return value of your functions
Let's imagine we have an addition function where the result is bounded:
(defn bounded-addition [a b {:keys [upper lower]}]
(cond-> (+ a b)
lower (max lower)
upper (min upper)))
Here are the initial specifications of our function:
(s/def ::upper number?)
(s/def ::lower number?)
(s/fdef bounded-addition
:args (s/cat :a number? :b number? :boundaries (s/keys :req-un [::upper ::lower])))
What happens when one passes the wrong arguments?
(stest/instrument `bounded-addition)
(bounded-addition 1 2 {})
You can instrument
and unstrument
:
(stest/unstrument `bounded-addition)
(bounded-addition 1 2 {})
What is the default - instrument
or unstrument
?
Let's check how our function behaves with valid random arguments
(s/exercise-fn bounded-addition)
We can also specify:
Let's imagine we have a multiplication function where the result is bounded:
(defn bounded-multiplication [a b {:keys [upper lower]}]
(-> (* a b)
#_(max lower)
#_(min upper)))
Here are the full specifications of our function:
(s/def ::upper number?)
(s/def ::lower number?)
(s/fdef bounded-multiplication
:args (s/and (s/cat :a number? :b number? :boundaries (s/keys :req-un [::upper ::lower]))
#(>= (-> % :boundaries :upper) (-> % :boundaries :lower)))
:ret number?
:fn #(<= (-> % :args :boundaries :lower) (:ret %) (-> % :args :boundaries :upper)))
Let's test our function (Test generation for free!):
(-> (stest/check `bounded-multiplication {::tc/opts {:num-tests 10}})
first
stest/abbrev-result)
What do you think about this amazing stuff?
powered by KLIPSE /