我有一个Ring处理程序,它使用几个函数来构建响应。如果这些函数中的任何一个抛出异常,则应该捕获它,以便在返回500之前可以编写自定义响应主体。
我正在为处理程序编写单元测试,并且我想确保如上所述处理由这些函数抛出的异常。我的直觉是在with-redefs
:
doseq
(doseq [f [ns1/fn1 ns1/fn2 ns2/fn1]]
(with-redefs [f (fn [& args] (throw (RuntimeException. "fail!"))]
(let [resp (app (request :get "/foo")))))]
(is (= (:status resp) 500))
(is (= (:body resp) "Something went wrong")))))
当然,鉴于with-redefs
想要更改变量的根绑定,它会将f
视为符号。有没有办法让它重新绑定f
引用的var?我怀疑我需要一个宏来完成这个,但我希望有人能想出一个聪明的解决方案。
答案 0 :(得分:2)
with-redefs
对于alter-var-root
的重复调用只是糖,所以你可以自己编写这些荒谬的表格,例如:
(doseq [v [#'ns1/fn1 #'ns1/fn2 #'ns2/fn1]]
(let [old @v]
(try
(alter-var-root v (constantly (fn [& args]
(throw (RuntimeException. "fail!")))))
(let [resp (app (request :get "/foo")))
(is (= (:status resp) 500))
(is (= (:body resp) "Something went wrong")))
(finally (alter-var-root v (constantly old))))))
答案 1 :(得分:0)
从amalloy's great answer开始,这是我在测试中使用的实用函数:
(defn with-mocks
"Iterates through a list of functions to-mock, rebinding each to mock-fn, and calls
test-fn with the optional test-args.
Example:
(defn foobar [a b]
(try (+ (foo a) (bar b))
(catch Exception _ 1)))
(deftest test-foobar
(testing \"Exceptions are handled\"
(with-mocks
[#'foo #'bar]
(fn [& _] (throw (RuntimeException. \"\")))
(fn [a b] (is (= 1 (foobar a b)))) 1 2)))"
[to-mock mock-fn test-fn & test-args]
(doseq [f to-mock]
(let [real-fn @f]
(try
(alter-var-root f (constantly mock-fn))
(apply test-fn test-args)
(finally
(alter-var-root f (constantly real-fn)))))))