This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-09
Channels
- # beginners (38)
- # boot (160)
- # cider (143)
- # cljs-dev (62)
- # cljsjs (2)
- # cljsrn (3)
- # clojure (278)
- # clojure-austin (8)
- # clojure-brasil (5)
- # clojure-greece (2)
- # clojure-italy (11)
- # clojure-russia (188)
- # clojure-sg (2)
- # clojure-spec (118)
- # clojure-uk (103)
- # clojurescript (87)
- # core-async (8)
- # cryogen (2)
- # cursive (12)
- # datomic (119)
- # emacs (13)
- # hoplon (4)
- # immutant (12)
- # off-topic (12)
- # om (54)
- # om-next (5)
- # onyx (1)
- # pedestal (2)
- # portland-or (2)
- # re-frame (58)
- # reagent (18)
- # ring-swagger (18)
- # rum (4)
- # spacemacs (4)
- # specter (3)
- # untangled (65)
- # yada (25)
I'm using exercise-fn and instrument at the repl but wanted to know if there was a standard way of wiring that in tests
I guess there are a few ways to do this: one would be just to call instrument on "normal" tests, then another could be replacing your test values with generated versions of it, which might or might not be difficult depending on what it is.
I haven't done any of it so far personally. Well actually just the instrumentation part on 1 project.
so, as an alternative of calling s/explain on all pre or post conditions, what about calling s/assert rather than s/valid ?
e.g.
(defn new-web-server [config]
{:pre [(s/assert ::config config)]}
(-> (map->WebServer config)
(using [:routes])))
i know the semantics aren't very clean (:pre is supposed to return true/false rather than an exception), but it does contain a lot more information
I guess the idea is to (maybe) someday promote most of it in spec itself, but I could be wrong
A last question for now, is it possible to specify custom generators only for clojure.spec.test/check
It's only a matter of visual preference, to be able to have simple specs in my main namespaces and specs with generators for tests
I think that means you want to use overrides
@gfredericks yes, but I only see support for those in exercise and exercise-fn
i.e: the generator overrides are only taken into account for the called fn. If the fn depends on other functions, they won't use the provided generators
like for stubbing in particular?
@gfredericks not sure I understand
I just don't know why else, when using c.s.t/check
, functions other than the one being tested would use generators
spec uses functions that return generators in a lot of places
Which can defer resolution, I assume. But maybe that can't help here.
that seems unfortunate
@gfredericks @mpenet thanks for your help today
I described my approach here: http://spootnik.org/entries/2017/01/09_an-adventure-with-clocks-component-and.html
I struggled to decouple the generators from the spec because otherwise it makes things harder to follow. My first iteration had with-gen
on the specs themselves and that made it much harder to explain what was going on
so, if i have a defrecord
for which I want to fdef and instrument certain functions defined within that record, how am I supposed to be referring those functions ?
(i think this is more related to clojure in general, and what the symbol names for functions inside records are)
AFAIK all record functions must be specified with protocols, so you can spec the protocol methods
@lmergen behavior is implemented on top of records through protocols, so as @schmee mentioned, you can specify protocol signatures as you would do functions
(defprotocol Encoder (encode [this])) (defrecord A [name] Encoder (encode [this] (str name)))
@lmergen in this case, (spec/fdef encode :args (s/cat :encoder #(satisfies? Encoder %)) :ret string?)
so if i have 5 different components (all using defrecord and the Lifecycle protocol), i want 5 different fdefs
the expected behavior of start in Lifecycle is that you return the same record possibly augmented with additional fields
(def component? #(satisfies Lifecycle %))
(spec/fdef start :args (s/cat :component component?) :ret component? :fn (= (.getClass (:component %)) (.getClass (:ret %))))
If you are really intent on spec'ing per-type behavior for your protocol, there is another much kludgier way.
extend
(http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/extend) takes a map of protocol implementation for types, which takes fns as args. You could implement Lifecycle this way and then spec the individual functions you have in the map
and should probably verify whether my entire system satisfies a certain spec, after it has been initialized
I don’t think it was mentioned above, but you cannot spec protocol functions
I suspect that it's an implementation issue, since protocol functions have very different function signatures
basically certain kinds of "function" calls(including protocols) are compiled differently and spec just handles the generic case
Am I missing a cleaner way to write this. Goal is to check that the options list has the required keys which are also declared in the data)
(s/def ::Select.props
(s/and
(s/keys :req-un [::value ::options ::value-key ::display-key ::on-change]
:opt-un [::placeholder ::disabled ::loading])
#(every? (fn [option] (contains? option (:value-key %))) (:options %))
#(every? (fn [option] (contains? option (:display-key %))) (:options %))))
This won't produce very specific errors
From today, you can easilly share your clojure.spec
related code snippets on klipse - it loads pretty fast
http://app.klipse.tech/?cljs_in.gist=viebel/cd7b4c26cf5a9fcc2d53e21021a25df0&eval_only=1
@olivergeorge so ::Select.props
describes a map, one of whose keys is :options
, which is a list of maps, each of which must contain values referred to by keys named :value-key
or :display-key
, which are in ::Select.props
-- is that right?
Correct
So I really want to confirm the options based on the map data
Like this movie inception
@kenny I gave it a try at simplifying your macro and came up with this:
(defmacro defspec-test
([name sym-or-syms] `(defspec-test ~name ~sym-or-syms nil))
([name sym-or-syms opts]
`(t/deftest ~name
(let [check-results# (clojure.spec.test/check ~sym-or-syms ~opts)]
(doseq [result# check-results#]
(t/is (nil? (:failure result#)) (clojure.spec.test/abbrev-result result#))
(when (nil? (:failure result#))
(println "[OK] - " (clojure.spec.test/abbrev-result result#))))))))
It can be simplified even more but I like the result so far. Hopefully it can be useful to somebody 🙂You want to use do-report
, not println
otherwise you'll break integrations with clojure.test
why? I dont know much about clojure.test actually 😕. I figured that the call to t/is
already took care of the integration. doesnt it?
The other important difference is that this is counting every single generative test instead of grouping them as one
ah I see what you mean. true the output is not as clean as with a normal test since you get the generated symbol but I still find the output better since in the previos macro I was only getting the stacktrace of an error. No idea which function failed nor other info. I dont know if it was a problem in my project though
@olivergeorge unfortunately, I think what you have is about as straightforward as you can get with what you want. While spec can nest sequential and associative structures easily, there is not another way (that I'm aware of) to relate various levels other than another predicate which is what you've done. If anything, I might combine the two additional predicates into one function, though you may find it gives you an undesirable level of detail:
(fn [{:keys [value-key display-key options]}]
(every? #(and (contains? % value-key)
(contains? % display-key))
options))