Skip to content
spying for tests
Clojure JavaScript HTML
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
resources/test Got the cljs tests running so that we have both clj and cljs tests Mar 30, 2016
src/bond Edit docstrings for style. Aug 21, 2019
test/bond/test assertions called?, called-times?, and called-with-args? (#39) Aug 6, 2019
.gitignore bump 0.4.0 Aug 6, 2019
circle.yml Add Code Coverage testing Sep 27, 2017
package.json Got the cljs tests running so that we have both clj and cljs tests Mar 30, 2016
project.clj bump 0.4.0 Aug 6, 2019

Bond CircleCI Status

Bond is a spying and stubbing library, primarily intended for tests.

[circleci/bond "0.4.0"]
  (:require [bond.james :as bond :refer [with-spy]]))

(defn foo [x]
  (let [shaken (with-out-str (prn :martini))]

(defn bar [y]
  (foo y))

(deftest foo-is-called
  (with-spy [foo]
    (bar 2)
    (is (= 1 (-> foo bond/calls count)))))

Bond provides one main macro, with-spy. It takes a vector of defn vars (vars that resolve to fns). Each var will be redefined for the scope of the macro, wrapping the function to track arguments and call counts. At any point during the scope, you can call (bond/calls f), where f is a spied fn. calls returns a seq of maps, one for each call to fb. Each map contains the keys :args, a seq of args the fn was called with, and one of :return or :throw.

Bond also provides with-stub!. It works the same as with-spy, but redefines the function to return (constantly nil) (default), while also spying on it. This is generally preferable to Clojure's built-in with-redefs macro since it will throw an exception if the mocked function is called with the wrong number of arguments. You can specify an arbitrary function instead of the default (constantly nil) by providing a [fn-var replacement-fn] vector in place of just the fn name:

  (:require [bond.james :as bond :refer [with-stub!]]))

(defn foo [x] ...)

(defn bar [y] ...)

(deftest foo-is-called
  (with-stub! [[foo (fn [x] "foo")]
               [bar (fn [y] "bar")]]
    (is (= ["foo" "bar"] [(foo 1) (bar 2)]))))
(deftest consecutive-stubbing
  (with-stub! [[foo [(fn [x] "foo1") 
                     (fn [x] "foo2") 
                     (fn [x] "foo3")]]
               [bar (fn [y] "bar")]]
    (is (= ["foo1" "foo2" "foo3" "bar"] [(foo 1) (foo 1) (foo 1) (bar 2)]))))

Private functions can also be stubbed or spyed:


(defn- foo [x] ...)
  (:require [bond.james :as bond :refer [with-stub!]]
            [ :as foo]))

(deftest foo-is-called
  (with-stub! [[foo/foo (fn [x] "foo")]]
    (is (= "foo" (#'foo/foo 1)))
    (is (= [1] (-> #'foo/foo bond/calls first :args)))))

There is also a with-stub macro which works like with-stub! but omits the argument check.

In addition to with-spy and with-stub!, Bond also provides with-spy-ns and with-stub-ns which can spy/stub every function in a namespace in one go:

  (:require [bond.james :as bond]
            [clojure.test :refer (deftest is)]))

(defn foo [] :foo)

(defn bar [] :bar)

(deftest you-can-stub-entire-ns
  (is (= :foo (foo)))
  (is (= :bar (bar)))
  (bond/with-stub-ns [[foo (constantly :baz)]]
    (is (= :baz (foo)))
    (is (= :baz (bar)))))


Distributed under the Eclipse Public License.

You can’t perform that action at this time.