简体   繁体   中英

Clojure.spec: how to spec data structures sensitive to random changes?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM