Fork me on GitHub

Trying to spec partition-all, but I get an exception. Repro:

Clojure 1.10.0
user=> (require '[clojure.spec.alpha :as s])
user=> (require '[clojure.spec.test.alpha :as stest])
user=> (s/fdef clojure.core/partition-all :args (s/cat :n pos-int?))
user=> (stest/instrument `partition-all)
user=> (partition-all 1)
Execution error (ClassCastException) at user/eval142 (REPL:1).
clojure.spec.test.alpha$spec_checking_fn$fn__3026 cannot be cast to clojure.lang.IFn$LO


that could be because of the type hint on the arity-1 of partition-all


yep, that's it


this is actually the first time I couldn’t instrument something on CLJ that I could on CLJS, normally it’s the other way around 😉


I guess instrument could look at the arglists and figure out if it needs to compile the wrapping fn to a primitive fn


How do people manage the seperation of concerns around app code, specs and generators? Generators are essentially a testing concern, but you also use want them at dev time so you can inspect sample values etc… Part of my issue is that writing generators eats up quite a few LOCs, so I’m tempted to put them in a different ns to the specs and app logic… I also feel like in clojure that they should be optional… which means you don’t really want them in the require tree in the production app. Are there any patterns people have for arranging these? Currently I just them all in the same ns — but at some point I worry it’ll be hard to see the wood for the trees.


Thinking also are there any lazy-loading patterns I can easily apply to my own generators?


Also you often want different generators depending on context


I know you can override them via st/check etc — but not really sure how to organise all these bits


@rickmoynihan clojure.spec.test/check takes overridable generators. I use those, if I don’t make a generator attached to the spec itself.


oh sorry, that was your last sentence


Hi, I am trying to write a generator... but no luck... I am trying to follow the examples from the test.check page... but no luck (yet)


it can't find certain functions for instance.. while as far as I can work out they should be in the clojure.spec.gen.alpha namespace


You may have to reference test check namespaces directly. Spec doesn’t expose all the stuff that’s available


frequency for instance.


@thomas are you using CLJ or CLJS?


maybe make a small repro of what you’re trying to do so we can take it from there?


ok will do. thank you. (I can't do it now, but I'll try later tonight) Thank you @borkdude


@thomas you know about lazy loading right?


you need to be aware that clojure.spec.gen.alpha generators are subtly different to test.check ones


I always forget the details… but IIRC generators from spec are wrapped in a 0 arg function to allow lazy loading… so if you’re trying to use test.check generators you need to wrap them one more time in a fn call… or something like that. 🙂


@borkdude: respeced looks useful… do you have any machinery to trigger st/check in a deftest and get a good error out from clojure.test when things go wrong?


I’ve written a few things like this in the past — but the results have always been lackluster.


yes, I’m doing that here: when a spec doesn’t conform, I see the thrown exception


the crucial part is (clojure.test/is (respeced.test/successful? stc-result#)), succesful? realizes the stc-result (it’s lazy) and checks if there’s at least one


yeah I’ve done things like that before — but yours looks like it might give better output…


it works fine for me


I’m guessing clojure.test just prints the error as (is (not (successful? ,,,)))


try it in the REPL and you’ll see 🙂


Yeah I’m going to 🙂


@borkdude: would you say a use case for rt/check-call is to check real sample data conforms to the spec then? i.e. as a way to check that the spec is valid, as much as the data/fdef?


@rickmoynihan check-call is made for checking fdefs on example based tests


e.g. to verify that your ret spec works given an example


one problem I’d like to tackle is: your function accepts arity 1 and 2, but you spec’ed only 2. there’s no way to detect this with stest/check since it only generates 2 args.


so fdefs could be insuffient. would be nice if that could be automatically detected.


it would be nice if you could generate data to detected that your fdef missed a case. I guess you can


related what I also find useful is a test of a s/conform against some example data… so you know you spec’d the right thing.


but then you find that clojure.test/is is effectively testing a boolean s/valid? is insufficient as you want to see the spec failure not just (is (not (s/valid? ,,,)))


that’s why I made check I think


this library is aimed at fdef checking


but I think there’s an equivalent need for spec checking too


as you say check requires an fdef


I was writing things like (is (not= :clojure.spec.alpha/invalid (s/conform :spec/here {:sample :data})) but you need to be careful using :clojure.spec.alpha/invalid in these macros because it can cause compilation errors due to :clojure.spec.alpha/invalid being used to check the macro syntax


but the reasoning there is that comparing (= ::s/invalid sample-result) gives you a meaningful error in clojure.test.


hah, yeah, I had a similar issue when spec’ing assoc, because then you cannot assoc the value :clojure.spec.alpha/invalid which Cursive does when you use the REPL 😛


solved that by writing my own ::any spec


yeah IIRC there’s a ticket open on the issue somewhere


yeah. one of the proposals there is to use a singleton object to represent invalid inside spec and only to the outside use the keyword


I think that makes sense

Alex Miller (Clojure team)17:01:42

you can use s/valid? rather than checking ::s/invalid


I used s/invalid?

Alex Miller (Clojure team)17:01:42

I don’t think a singleton object is a feasible solution

Alex Miller (Clojure team)17:01:51

I’m not even sure I agree it’s a problem


@alexmiller It’s a problem when you instrument a function that must be able to deal with ::s/invalid as one of the arguments. This is important in tooling such as Cursive where ::s/invalid is remembered as REPL state for example

Alex Miller (Clojure team)17:01:38

there are a very small number of such functions and some workarounds even for those cases


yes, a workaround is writing your own ::any 😉

Alex Miller (Clojure team)17:01:26

I consider “do nothing” to be a leading contender alternative for that ticket


how many votes are representative of “considered important enough by the community” in general for a CLJ Jira issue?

Alex Miller (Clojure team)17:01:01

votes are about attention, not answers

Alex Miller (Clojure team)17:01:44

if you’re not spec’ing core functions used by spec, how often is this an issue?

Alex Miller (Clojure team)17:01:52

b/c that’s when I’ve seen people raise it


probably tooling, but then it would only be an issue for the developer of that tooling

Alex Miller (Clojure team)17:01:03

I don’t consider this a settled result (which is why the ticket is still open)

Alex Miller (Clojure team)17:01:10

that’s just my current thinking on it

Alex Miller (Clojure team)17:01:07

changing topics, I just merged a giant refactor in spec-alpha2 in case anyone is interested

Alex Miller (Clojure team)17:01:46

although since it’s a refactoring rather than new stuff, it’s not particularly exciting


I think this issue is more important than the any problem:


that’s not only about self-spec’ing

Alex Miller (Clojure team)17:01:53

I haven’t had time to look at it seriously but I am aware of it


about spec-alpha2: cool! I’ll try it out soon

Alex Miller (Clojure team)17:01:06

there are some subtly important differences in the api for callers

Alex Miller (Clojure team)17:01:12

I will try to write about those in my journal today rather than spew them here

👍 20

What approach do folks use to handle the namespacing of nested keys. We are trying to spec check the interface to an external service and the payload is a nested map. Namespaced keywords would seem to imply having to create a namespace for each nesting which isn’t ideal. Alternatively, we could generate the specs but this seems to have its own problems. As far as I can tell this would imply having to compose macros which seems excessive. Additionally, the caller side would have to construct the long form of these keywords in order to pull out the necessary data since there would be no namespaces to alias with this approach. Is there another approach that I’m missing? Its also possible that spec isn’t appropriate for this use case.


@tyler a similar question was asked not too long ago here


Is it in the recent history? I’m having trouble searching for it.


you don't have to create "real" namespaces for the keys, you can qualify keys with arbitrary prefixes e.g. :fake-ns/foo


We sometimes use "dotted-path" namespaces like :order.line-item/qty

👍 5

Thank you