heya
is it possible to rename a key with s/keys
?
I'd like to do something like this
(s/def ::msg (s/and string? #(< 20 (count %))))
;; TODO: declaring a spec for a limited :db/id doesn't sound right. Figure out a better way.
(s/def :db/id (into #{} (range 1 10)))
(s/def ::map-datom (s/keys :req [:db/id ::msg]))
(s/def ::simple-tx (s/coll-of ::map-datom :kind vector? :min-count 0 :max-count 3))
but instead of (s/def :db/id
, I'd like to do (s/def ::id
and then on s/keys
say that ::id
is required but should show up as :db/id
I'd like to do this because I don't want to be declaring the spec for the real :db/id
, but would like to have an alternative version of it for testing
in short, no - the whole idea with spec is that attributes are primary and have meaning and maps are just aggregations of attributes
if you want a broader definition of ::db/id, then your spec should reflect that
ok, thank you for explaining it to me
if I want to just generate test data that is a subset of all possible data, should I be using something else?
@filipematossilva: It sounds like you might be complecting generating data with specing. If in your tests you want to generate known id’s that are a subset of valid id’s, you can probably just pass a generator for that set where you need it.
yes, I think I am
but s/keys
does not support inline value specs (by design, according to the docs), so I don't think I can do that
(unless, of course, I am misunderstanding what you propose)
an alternative is to generate the test data with exercise, and then map over the results to change the key
which sounds fair enough, but I wanted to inquire first
you can pass generator overrides when doing most of the functions that generate in spec, but you still have to generate data that conforms to the spec
ah, then this was just something I did not know existed
or rather https://clojuredocs.org/clojure.spec.alpha/with-gen, as that seems to have examples
Totally! :-)
When I first started with spec I made the mistake of over speccing to get spec to try and generate test data of the right shape… but now prefer the alternative of specing a little more broadly but using :gen
’s to generate the more precise data I want.
Obviously it’s all trade offs.
Anyway I was just suspecting Filipe might be falling into this same trap.
yes, I was 🙂
thank you
I'll try to fiddle with the :gen
option on s/keys and see where that takes me
:thumbsup: hope it helps
@rickmoynihan I'm trying to use the :gen
key on s/keys
, but I don't quite follow how I can use it to replace a single def
is that possible? or does :gen
need to override how everything is generated
if you have an example of using it with s/keys
it would be super useful
oh, I think this is the idea?
(s/def :db/id pos-int?)
(s/def ::small-pos-int? (into #{} (range 1 10)))
(s/def ::map-datom (s/keys :req [:db/id]))
(def small-pos-int-gen (s/gen ::map-datom {:db/id #(s/gen ::small-pos-int?)}))
(s/def ::small-id-map-datom (s/keys :req [:db/id]
:gen (fn [] small-pos-int-gen)))
(s/exercise ::small-id-map-datom 10)
;; => ([{:db/id 5} {:db/id 5}] [{:db/id 3} {:db/id 3}] [{:db/id 1} {:db/id 1}] [{:db/id 1} {:db/id 1}] [{:db/id 7} {:db/id 7}] [{:db/id 8} {:db/id 8}] [{:db/id 6} {:db/id 6}] [{:db/id 8} {:db/id 8}] [{:db/id 6} {:db/id 6}] [{:db/id 2} {:db/id 2}])
making the real spec, then making another spec that has a generator that takes the real spec generator and adds an override
That’s not quite what I was suggesting…
(s/def ::foo integer?)
(s/def ::foo-map (s/keys :req-un [::foo]))
;; The general generator (generates negative integers too)
(s/exercise ::foo-map);; => ([{:foo -1} {:foo -1}] [{:foo 0} {:foo 0}] [{:foo 0} {:foo 0}] [{:foo 0} {:foo 0}] [{:foo 3} {:foo 3}] [{:foo -2} {:foo -2}] [{:foo -7} {:foo -7}] [{:foo -37} {:foo -37}] [{:foo -2} {:foo -2}] [{:foo -3} {:foo -3}])
;; An overriden tighter generator generating just 1 and 2 values for :football:
(s/exercise ::foo-map 10 {::foo-map (fn [] (s/gen #{{:foo 1} {:foo 2}}))});; => ([{:foo 1} {:foo 1}] [{:foo 2} {:foo 2}] [{:foo 1} {:foo 1}] [{:foo 2} {:foo 2}] [{:foo 2} {:foo 2}] [{:foo 1} {:foo 1}] [{:foo 1} {:foo 1}] [{:foo 2} {:foo 2}] [{:foo 2} {:foo 2}] [{:foo 2} {:foo 2}])
@filipematossilva: You can override on s/exercise
, or st/check
as well, so you can tailor your generation there rather than in the specs if you want.
ah on exercise itself
I see now
(s/def :db/id pos-int?)
(s/def ::small-pos-int? (into #{} (range 1 10)))
(s/exercise :db/id 10 {:db/id #(s/gen ::small-pos-int?)})
I understand now
thank you for taking the time to make the examples for me
:thumbsup:
it was very helpful
essentially s/exercise
/ st/check
are the testing entry points to spec; so you can split the concerns of specing and overriding generation/testing at those entry points… whilst s/conform
s/valid?
and s/explain-xxx
are the checking side of spec — and consequently don’t support generators at all (because they’re a different concern)
at least that’s how I think of it
There are probably more nuanced explanations 🙂
that sounds much more sensible than I what was attempting
its ok been there, done it, got burned! 🙂