Skip to content

Instantly share code, notes, and snippets.

@overthink overthink/mocks.clj

Last active Dec 1, 2015
What would you like to do?
(ns foo.core
"Looking at ways to mock out records when testing and also using schema."
[schema.core :as s]))
;; approach 1 (problematic for mocks) --------------------------------------------------
(s/defrecord Thing
[name :- s/Str
age :- s/Int])
(s/defn f
[thing :- Thing]
(:name thing))
(let [real-thing (->Thing "mark" 100)
mock-thing {:name "mark" :age 100}]
;; ok
(f real-thing)
;; Input to f does not match schema: [(named (not (instance? foo.core.Thing a-clojure.lang.PersistentArrayMap)) thing)]
;; While true, it's not what we want :)
#_(f mock-thing)))
;; approach 2 (schema separate from record, considerably better for mocks) ---------
;; non-annotated record
(defrecord Thing2
[name age])
;; record's schema is separate from record
(def ThingLike
{:name s/Str
:age s/Int})
;; associate schema with record
(s/record Thing2 ThingLike)
(s/defn g
[thing :- ThingLike]
(:name g))
(let [real-thing (->Thing2 "mark" 100)
mock-thing {:name "mark" :age 100}
broken-mock {:name "mark" :age "one hundred"}]
;; ok
(g real-thing)
;; mock is ok!
(g mock-thing)
;; fails validation as expected
#_(g broken-mock)
;; approach 3 (protocols, probably the best, most rigid) -------------------------
(defprotocol IThing
(thing-name [this]))
;; non-annotated record
(defrecord Thing3 [name age]
(thing-name [_] name))
(s/defn h
[thing :- (s/protocol IThing)]
(thing-name thing))
(let [real-thing (->Thing3 "mark" 100)
mock-thing (reify IThing
(thing-name [_] "mark"))
broken-mock {:name "mark" :age 100}]
;; ok
(h real-thing)
;; mock is ok, implements protocol
(h mock-thing)
;; broken mock doesn't participate in protocol so it's no good, in spite of "looking" right
#_(h broken-mock)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.