Other languages have property based testing libraries, like Haskell QuickCheck. How does Clojure spec differ from such libraries? Or is it just a property based testing framework for Clojure?
Clojure's analog for QuickCheck would be test.check. Clojure.spec relies on test.check for generative testing, but spec can be used for much more than testing.
Test.check provides tools for generative and property-based testing. Clojure.spec allows you to write specifications for data, and can create generators from those specs automatically. Using test.check alone, you'd need to create non-trivial generators by hand. With clojure.spec, generators can (with some exceptions) be derived from your spec.
(s/def ::my-spec string?) ;; a trivial spec, any string will do
(sgen/sample (s/gen ::my-spec)) ;; create a generator from spec and get samples
;;=> ("" "P" "B" "" "qV" "im4P" "Zf" "" "rL24" "wAV7z")
These generators can be used to generate input data for functions of which you want to test properties. You can write property-based tests using just test.check, and you can also write some property-based tests for functions using clojure.spec. Here's an example of a function that takes a string and returns the "doubled" string:
(defn doubler [s] (str s s))
(s/fdef doubler
:args (s/cat :s string?)
:ret string?
:fn (fn [{:keys [args ret]}]
(= (* 2 (count (:s args))) (count ret))))
(stest/check `doubler)
The s/fdef
spec defines the properties we want from our function: it takes one string, returns a string, and the returned string should be twice as long as the input. We use check
to ensure these properties hold for a bunch of randomly generated inputs.
© 2022 - 2024 — McMap. All rights reserved.