How does Clojure spec differ from property-based testing libraries, such as Haskell QuickCheck?
Asked Answered
I

1

5

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?

Ignace answered 18/10, 2017 at 21:36 Comment(1)
Also see "what is spec" https://mcmap.net/q/1583324/-what-is-clojure-specHoldup
S
8

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.

Take a look at the overview and guide for more.

Squirmy answered 18/10, 2017 at 23:42 Comment(6)
What does differentiate spec from test.check is only its ability to automatically create test generators? Is that also what differentiates spec from QuickCheck? Could you present some examples of spec uses outside testing?Ignace
There's no reason to compare clojure.spec with test.check or any other property-based testing library; it has many uses and purposes beyond testing, the core of which is writing specifications for data structures. The linked overview does a great job of explaining this, and the linked guide has many examples of spec usage outside testing.Squirmy
When you say specifications for data structures, do you mean for human consumption? Or is there something a program can do with it (besides testing)?Ignace
In the guide, I found examples about specification, testing, explaining test results (spec violations) and generators. In the what is spec question I found "Conform" a value which gives you a parsed and destructured version of the value" outside testing.Ignace
Yes, the specs are both human- and machine-readable. For example, a program can use spec to assert some data (maybe user input) conforms to a specification. Building on that, there are libraries like Expound that can render spec problems in a more human-readable format. Then there's Phrase which is meant for turning spec problems into end-user-friendly messages.Squirmy
In a nutshell, spec goal is to create specifications that can be used for testing and for human consumption (there are tools to make them more human readable). When compared to other tools (QuickCheck, etc), spec is more expressive, allowing descriptions that can be used in place of textual specifications. Did I get it right?Ignace

© 2022 - 2024 — McMap. All rights reserved.