Mocking protocols should be no different than mocking functions, you need to consider that the first dispaching parameter is this
and so the mocking function should take that type in consideration.
For instance, given a protocol P
:
(defprotocol P
(foo [this])
(bar-me [this] [this y]))
Extended for type Integer
(extend-protocol P
Integer
(foo [this]
(+ this 4))
(bar-me [this]
(* this 5))
(bar-me [this y]
(+ this y)))
You can check a couple things first, there's no implementation for Long
:
(foo 3)
=> IllegalArgumentException No implementation of method: :foo of
protocol: #'P found for class: java.lang.Long
clojure.core/-cache-protocol-fn (core_deftype.clj:541)
Works as expected for ints
:
(foo (int 3))
=> 7
Now define the fact and provide the protocol function as you need:
(fact
(foo (int 3)) => 7
(provided (foo 3) => 8))
In this case it properly fails since the mock is returning 8
instead of 7
for the specified input.
FAIL at (test.clj:20)
Expected: 7
Actual: 8
If value mocks are not enough and you need to provide an alternative implementation instead, take a look at with-redefs-fn, you can wrap tested functions with it.
=> (defn f [] false)
=> (println (f))
;; false
=> (with-redefs-fn {#'f (fn [] true)}
#(println (f)))
;; true
There's also a discussion in GitHub about his with a couple alternatives for runtime dispatching mocks.