Skip to content

Instantly share code, notes, and snippets.

@grzm
Last active June 30, 2017 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grzm/0ada176caee5bcdab39d820577ed3823 to your computer and use it in GitHub Desktop.
Save grzm/0ada176caee5bcdab39d820577ed3823 to your computer and use it in GitHub Desktop.
Overriding generator function spec in `stest/instrument`
(ns spec-ex.core
(:require
[clojure.spec.alpha :as s]
[clojure.spec.gen.alpha :as gen]
[clojure.spec.test.alpha :as stest]))
;; [org.clojure/spec.alpha "0.1.123"]
;; The goal is to stub functions which require some kind external
;; dependency, such as a service or other I/O.
(defprotocol Y
(-do-y [r]))
(def y? (partial satisfies? Y))
(s/def ::y y?)
;; Protocol methods can't be spec'd, so wrap them in a function.
(defn do-y [r]
(-do-y r))
(s/fdef do-y :args (s/cat :y-er ::y))
;; Example of the protocol implementation that we're going to stub.
(defrecord BadYer []
Y
(-do-y [_] (throw (Exception. "can't make me!"))))
;; Confirm BadYer instances are valid with respect to the protol spec.
(s/valid? ::y (->BadYer))
;; => true
;; And confirm BadYer instances will throw when called.
(try
(do-y (->BadYer))
(catch Exception e
(.getMessage e)))
;; => "can't make me!"
(def y-gen (gen/return (->BadYer)))
;; Confirm generator works as expected:
(gen/sample y-gen 1)
;; => (#spec_ex.core.BadYer{})
;; We want to stub `do-y`, providing y-gen as a generator for `::y`
(try
(stest/instrument `do-y {:stub #{`do-y}
:gen {::y (fn [] y-gen)}})
(catch Exception e
(ex-data e)))
;; => #:clojure.spec.alpha{:path [:y-er], :form :spec-ex.core/y, :failure :no-gen}
;; However, we *can* stub `do-y` if we replace its spec.
(stest/instrument `do-y
{:stub #{`do-y}
:spec {`do-y (s/fspec
:args (s/cat :y-er (s/with-gen ::y
(fn [] y-gen))))}})
;; => [spec-ex.core/do-y]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment