This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-05-24
Channels
- # announcements (1)
- # babashka (86)
- # beginners (75)
- # boot-dev (1)
- # cljdoc (18)
- # cljs-dev (1)
- # cljsrn (67)
- # clojure (127)
- # clojure-australia (1)
- # clojure-dev (2)
- # clojure-europe (9)
- # clojure-nl (2)
- # clojure-serbia (2)
- # clojure-spec (11)
- # clojure-uk (14)
- # clojurescript (17)
- # code-reviews (4)
- # conjure (37)
- # core-async (11)
- # datomic (21)
- # emacs (1)
- # helix (36)
- # jobs (6)
- # malli (1)
- # meander (20)
- # re-frame (13)
- # reagent (49)
- # remote-jobs (11)
- # rum (1)
- # sci (1)
- # shadow-cljs (29)
- # sql (17)
- # vim (2)
Personally I recommend writing two generation functions, one that takes a generation depth and generates a full data structure to that depth, and another that takes a generation depth and generates a "narrow" structure to the given depth. This way you can test with the first one to a low depth to see "wide" structure generation, and use a much higher generation depth for the narrow one, using a weighted rng to choose which one to generate when using a with-gen form in the spec.
Or as you've noted, recursive-gen already provides a reasonable solution, in that case you can also use that with spec's facilities to wrap something with a custom generator.
(require '[clojure.test.check.generators :as gen])
(s/def ::bool
boolean?)
(def data-gen (gen/recursive-gen gen/vector gen/boolean))
(s/def ::vec
(s/with-gen
(s/coll-of ::data)
(gen/vector data-gen)))
(s/def ::data
(s/with-gen
(s/or :bool ::bool
:vec ::vec)
data-gen))
For reference, the clojure spec generators are just a reexport of the functions in clojure.test.check.generators, which means that you can use them interchangeably.
well, almost interachangeably - most of the spec apis actually take a no-arg function that returns a generator instead of a generator (to allow for dynamic require/invoke)
I remember wondering why e.g. with-gen
accepts a "generator returning function" instead of the generator itself; can you clarify what you mean by that "dynamic require/invoke" functionality? Something to do with requiring additional namespaces within the function but only if the generator is actually invoked (e.g. in generative testing)?
yes, that
by putting it in a thunk, we can avoid dynaloading the test.check.generators ns
I see, thank you
Oh that's good to know. Thanks for the heads up on that.