3

假设您有 a::givee和 a ::giver

(s/def ::givee keyword?)
(s/def ::giver keyword?)

那形成一个unq/gift-pair

(s/def :unq/gift-pair (s/keys :req-un [::givee ::giver]))

然后你有一个:unq/gift-historywhich is a vectorof unq/gift-pair

(s/def :unq/gift-history (s/coll-of :unq/gift-pair :kind vector?))

最后,假设您要替换其中的:unq/gift-pair一个vector

(defn set-gift-pair-in-gift-history [g-hist g-year g-pair]
  (assoc g-hist g-year g-pair))
(s/fdef set-gift-pair-in-gift-history
        :args (s/and (s/cat :g-hist :unq/gift-history
                            :g-year int?
                            :g-pair :unq/gift-pair)
                     #(< (:g-year %) (count (:g-hist %)))
                     #(> (:g-year %) -1))
        :ret :unq/gift-history)

一切正常:

(s/conform :unq/gift-history
           (set-gift-pair-in-gift-history [{:givee :me, :giver :you} {:givee :him, :giver :her}] 1 {:givee :dog, :giver :cat}))
=> [{:givee :me, :giver :you} {:givee :dog, :giver :cat}]

直到我尝试stest/check它:

(stest/check `set-gift-pair-in-gift-history)
             clojure.lang.ExceptionInfo: Couldn't satisfy such-that predicate after 100 tries.
java.util.concurrent.ExecutionException: clojure.lang.ExceptionInfo: Couldn't satisfy such-that predicate after 100 tries. {}

我曾尝试使用s/int-in限制向量计数(认为这可能是问题)但没有成功。

关于如何(stest/check `set-gift-pair-in-gift-history)正确运行的任何想法?

谢谢你。

4

1 回答 1

5

问题是向量的生成器和集合中的索引是独立的/不相关的。随机向量和整数不满足这些标准:

#(< (:g-year %) (count (:g-hist %)))
#(> (:g-year %) -1)

对于check这个函数,你可以提供一个自定义生成器来生成随机:unq/gift-history向量,并根据该向量的大小为索引构建另一个生成器:

(s/fdef set-gift-pair-in-gift-history
  :args (s/with-gen
          (s/and
            (s/cat :g-hist :unq/gift-history
                   :g-year int?
                   :g-pair :unq/gift-pair)
            #(< (:g-year %) (count (:g-hist %)))
            #(> (:g-year %) -1))
          #(gen/let [hist (s/gen :unq/gift-history)
                     year (gen/large-integer* {:min 0 :max (max 0 (dec (count hist)))})
                     pair (s/gen :unq/gift-pair)]
             [hist year pair]))
  :ret :unq/gift-history)

这是使用 test.check 的let宏,它比bind/更方便,fmap它允许您使用看起来像常规的代码组合/组合生成器let。自定义生成器将参数向量返回给函数。

于 2018-06-26T00:29:42.747 回答