Fork me on GitHub
#clojure-spec
<
2016-10-28
>
drewr17:10:07

I'm having a time with clojure.test.spec/check

drewr17:10:17

{:spec
 (fspec :args (cat :m :runbld.store/es-opts) :ret string? :fn nil),
 :sym runbld.store/make-connection,
 :failure #error {
 :cause "clojure.test.check.generators.Generator cannot be cast to clojure.lang.IFn"
 :via
 [{:type java.lang.ClassCastException
   :message "clojure.test.check.generators.Generator cannot be cast to clojure.lang.IFn"
   :at [clojure.spec$map_spec_impl$reify__13764 gen_STAR_ "spec.clj" 821]}]
 :trace
 [[clojure.spec$map_spec_impl$reify__13764 gen_STAR_ "spec.clj" 821]
  [clojure.spec$gensub invokeStatic "spec.clj" 269]
  [clojure.spec$re_gen invokeStatic "spec.clj" 1565]
  [clojure.spec$re_gen$ggens__14211$gen__14212 invoke "spec.clj" 1554]
  [clojure.core$map$fn__6882 invoke "core.clj" 2739]
  [clojure.lang.LazySeq sval "LazySeq.java" 40]
  [clojure.lang.LazySeq seq "LazySeq.java" 49]
  [clojure.lang.RT seq "RT.java" 525]
  [clojure.core$seq__6416 invokeStatic "core.clj" 137]

drewr17:10:23

which comes from this fdef

(s/fdef make-connection
        :args (s/cat :m ::es-opts)
        :ret string?)
(defn make-connection
  [args]
  (http/make args))

hiredman17:10:16

you are using a test.check generator directly somewhere, maybe for ::es-opts

hiredman17:10:34

you need to wrap them in a thunk

drewr17:10:36

yeah, I suspected that, but I don't :require test.check anywhere

drewr17:10:04

ah wait, I see it now

drewr17:10:12

yeah ::es-opts was it

drewr17:10:04

I was getting that exception for a with-gen in a separate place and kept thinking it was the same place

cap10morgan18:10:33

What are folks' thoughts on generative testing w/ spec on stateful fns (in this case modifying an atom)? How do you setup enough variations on the state for meaningful tests? Or is the answer that I should go to test.check directly instead of relying on what clojure.spec generates?

bhagany18:10:49

@cap10morgan: I haven’t done anything stateful yet, but if I had special generative needs, I’d reach for passing a custom generator in with-gen first. If I understand you correctly, this is what you’re reaching for with the idea to use test.check directly.

cap10morgan18:10:27

@bhagany OK, thanks. You answered my next question too. 🙂

seancorfield18:10:46

@cap10morgan I’d try to separate the logic from the state and test the logic separately if possible.

cap10morgan18:10:26

@seancorfield Hmm, that's a good idea. I need to get into the habit more often. Thanks!

seancorfield18:10:27

I was just having a similar conversation in #component 🙂

drewr18:10:44

how do you figure out which spec or gen is problematic when you get Couldn't satisfy such-that predicate after 100 tries.

drewr18:10:08

the stacktrace doesn't provide any clues that I can see

hiredman18:10:18

I think alexmiller has mentioned that as a pain point, that error comes out of test.check and plumbing the spec information through from spec to test.check and back again hasn't been done

hiredman18:10:34

I would start looking at your s/ands I guess

hiredman18:10:12

if I recall, the way generators for s/and specs are constructed is you take the generator for the first spec in the s/and, and then such-that the rest of the specs (as predicates)

hiredman18:10:58

so if you have a really generic first thing, and more specific predicates afterwards, you can easily end up with a such-that that doesn't work

drewr18:10:11

yep, that's exactly what it was

drewr18:10:37

(s/and string?
         #(.startsWith % "http"))

drewr18:10:05

I had a string, but it was "foo"

Alex Miller (Clojure team)18:10:51

there is an exactly almost the same as this in the spec guide http://clojure.org/guides/spec

Alex Miller (Clojure team)18:10:10

that shows how to make a custom generator for it

drewr18:10:44

@alexmiller it wasn't that I misunderstood the spec, I just couldn't find the problematic one

drewr18:10:01

thanks for that doc!