Skip to content

Commit 6d5d3ed

Browse files
committed
issue-2: support mocking private functions
1 parent ea0ef7b commit 6d5d3ed

File tree

5 files changed

+67
-20
lines changed

5 files changed

+67
-20
lines changed

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ Temporarily redefines `var` while executing `body`.
1919
If the right-hand side of a spec is a value, then it will create a function constantly returning the value (stub).
2020
If the right-hand side of a spec is a function, then the var-symbol will temporarily be replaced by the function.
2121

22-
### Example
22+
### Features & Example
23+
24+
#### Track mock's invocation history
2325

2426
```clojure
2527

@@ -43,6 +45,22 @@ If the right-hand side of a spec is a function, then the var-symbol will tempora
4345

4446
```
4547

48+
#### Mock private functions with ease
49+
50+
```clojure
51+
(ns ns-a)
52+
(defn- g [] true)
53+
(defn f [a] (g))
54+
55+
(ns ns-b)
56+
(deftest mock-private-test
57+
(with-mock [#'ns-a/g "baz"]
58+
(is (= (f "foo") "baz"))))
59+
60+
```
61+
62+
(Note: generally, it's not a good idea to mock private functions)
63+
4664
## License
4765

4866
Copyright © 2017 Ming

project.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
(defproject mock-clj "0.1.0"
1+
(defproject mock-clj "0.2.0"
22
:description "A minimalist & non-invasive API for mocking in Clojure"
33
:url "https://github.com/zhming0/mock-clj"
44
:license {:name "Eclipse Public License"

src/mock_clj/core.clj

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,49 @@
55
Internal functions - ignore these
66
"""
77

8+
; Check if input is like '(var x) or #'x
9+
(defn- var-symbol? [v]
10+
(and
11+
(seq? v)
12+
(= 2 (count v))
13+
(= (first v) 'var)))
14+
15+
(defn- try-strip-var [v]
16+
(if (var-symbol? v)
17+
(second v)
18+
v))
19+
820
(defmacro make-mock
9-
([m] `(make-mock ~m nil))
10-
([m stub]
11-
`(with-meta
12-
(fn [& ~'args]
13-
(swap! (-> ~m meta :args) conj ~'args)
14-
; If stub is a function, execute it
15-
(if (fn? ~stub)
16-
(apply ~stub ~'args)
17-
~stub))
18-
{:args (atom [])})))
19-
20-
(defn gen-redefs [[m stub & spec]]
21-
(into
22-
[m `(make-mock ~m ~stub)]
23-
(when spec
24-
(gen-redefs spec))))
21+
([] `(make-mock nil))
22+
([stub]
23+
`(let [~'state (atom [])]
24+
(with-meta
25+
(fn [& ~'args]
26+
(swap! ~'state conj ~'args)
27+
; If stub is a function, execute it
28+
(if (fn? ~stub)
29+
(apply ~stub ~'args)
30+
~stub))
31+
{:args ~'state}))))
32+
33+
(defn- gen-redefs [[m stub & spec]]
34+
(let [sm (try-strip-var m)]
35+
(into
36+
[sm `(make-mock ~stub)]
37+
(when spec
38+
(gen-redefs spec)))))
39+
40+
(defn- if-var->obj [m]
41+
(if (var? m)
42+
(deref m)
43+
m))
2544

2645
"""
2746
------------------------------------
2847
APIs
2948
"""
3049

31-
(defn calls [m] @(-> m meta :args))
50+
(defn calls [m] @(-> m if-var->obj meta :args))
3251

3352
(defn last-call [m] (last (calls m)))
3453

test/mock_clj/core_test.clj

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(ns mock-clj.core-test
22
(:require [clojure.test :refer :all]
3-
[mock-clj.core :refer :all]))
3+
[mock-clj.core :refer :all]
4+
[mock-clj.sample-private-ns]))
45

56
(defn foo [a & rst]
67
(str "foo" a))
@@ -66,3 +67,9 @@
6667
(is (called? foo))
6768
(reset-calls! foo)
6869
(is (not (called? foo)))))
70+
71+
(deftest private-fn-test
72+
(with-mock [mock-clj.sample-private-ns/private-fn (constantly "ok")]
73+
(= "ok" (#'mock-clj.sample-private-ns/private-fn 2))
74+
(is (called? #'mock-clj.sample-private-ns/private-fn))
75+
(is (= (last-call #'mock-clj.sample-private-ns/private-fn) [2]))))

test/mock_clj/sample_private_ns.clj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(ns mock-clj.sample-private-ns)
2+
3+
(defn- private-fn [a] "bar")

0 commit comments

Comments
 (0)