I'm trying Interactive Development with clojure.spec and have a problem with specs for function arguments that cannot change a lot. For instance, if a function receives a file name as argument, I can write the following spec:
(s/def ::file-name string?)
(s/fdef test-fn :args (s/cat :x ::file-name))
If I exercise it:
(s/exercise-fn `test-fn)
The function will be tested with lots of random file names that will fail to read any file. It is possible to limit the file names to a set of valid and invalid file names. That is fine for testing, but it will make the spec specific to the chosen set.
That is a problem not only with file names, but with any complex data structure where even small random changes may render it useless.
What should I do? Any relevant technique or good practice?
That is fine for testing, but it will make the spec specific to the chosen set.
This is where custom generators are useful:
(s/def ::file-name
(s/with-gen string? #(gen/elements #{"good.txt" "bad.txt"})))
(s/fdef test-fn :args (s/cat :x ::file-name))
(Where gen
is clojure.test.check.generators
or clojure.spec.gen.alpha
.)
Now your spec's predicate is still string?
but the values generated from this spec will always be from #{"good.txt" "bad.txt"}
. You can compose generators in several ways, for example you could make a generator that took from a string set ~50% of the time and generated a purely "random" string for the other ~50%.
FYI clojure.spec.test.alpha/check
also takes an opts
map that allows you to override/specify generators.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.