`instrument`不尊重`:stub`的`:gen`覆盖。
(require '[clojure.spec.alpha :as s])
(require '[clojure.spec.gen.alpha :as gen])
(require '[clojure.spec.test.alpha :as stest])
;; [org.clojure/spec.alpha "0.1.123"]
;; 目标是模拟需要某些外部依赖的功能,例如服务或其他I/O。
;; (defprotocol Y
(-do-y [r]))
(def y? (partial satisfies? Y))
(s/def ::y y?)
;; 协议方法无法进行规范,所以在一个函数中包装它们。
(defn do-y [r]
(-do-y r))
(s/fdef do-y :args (s/cat :y-er ::y))
;; 这是我们要模拟的协议实现示例。
(defrecord BadYer [])
Y
(-do-y [_] (throw (Exception. "can't make me!"))) ;
)
;; 用协议规范验证BadYer实例的有效性。
(s/valid? ::y (->BadYer))
;; => true
;; 确认当被调用时,BadYer实例将引发异常。
(try
(do-y (->BadYer))
(catch Exception e
(.getMessage e)))
;; => "can't make me!"
(def y-gen (gen/return (->BadYer)))
;; 确认生成器按预期工作
(gen/sample y-gen 1)
;; => (#spec_ex.core.BadYer{})
;; 我们希望模拟`do-y`,为`::y`提供y-gen作为生成器
(try
(stest/instrument `do-y
:stub #{`do-y}
(catch Exception e
:gen {::y (fn [] y-gen)}})
)
;; => #:clojure.spec.alpha{:path [:y-er], :form :spec-ex.core/y, :failure :no-gen}
;; 但是,如果替换其规范,我们可以模拟`do-y`。
(stest/instrument `do-y
{:stub #{`do-y}
:spec {`do-y (s/fspec
:args (s/cat :y-er (s/with-gen ::y
:func [] y-gen))))}})