如何使用`with-redefs`来始终从函数中抛出异常

时间:2015-11-10 08:42:38

标签: unit-testing clojure

我想单元测试代码的异常处理部分。为了做到这一点,我使用with-redefs来重新绑定可以抛出异常以在测试期间抛出异常的API。我的测试功能看起来像这样

(deftest exception-handling
  (testing "Map exception to Ring-response map"
    (with-redefs [clj-http/get
                  (constantly (throw (ex-info "unexpected error" {:cause "A terrible calamity"})))]
      (is (= 500
        (:status
          (some-function-calling-http-get arg))))
    )
  )
)

运行lein test会导致错误消息:

    ERROR in (exception-handling) (core.clj:4593)
Uncaught exception, not in assertion.
expected: nil
  actual: clojure.lang.ExceptionInfo: unexpected error
 at clojure.core$ex_info.invoke (core.clj:4593)

(constantly (throw...中使用with-redefs或仅声明thrown?引发异常也会导致同样的错误。

基本上我正在寻找constantly的宏观版本。

3 个答案:

答案 0 :(得分:4)

constantly是一个函数,而不是宏,因此(constantly (throw ...))会立即抛出错误。

如果你想要一个每次调用都会抛出错误的函数,你需要这样的东西:

(with-redefs [clj-http/get (fn [& _] (throw (ex-info "unexpected error"
                                                     {:cause "A terrible calamity"})))]
  ...)

答案 1 :(得分:1)

您正在以错误的方式接近此问题:您的测试期望clj-http的正常行为返回状态500,但您的with-redef实际上完全覆盖了任何clj-http代码。换句话说,您的测试显示现在对clj-http/get的所有调用始终(constantly)都会引发异常。你想要的是clj-http/get总是返回500.你可以使用clj-http-fake来做到这一点。

答案 2 :(得分:0)

您还可以使用clj-http-fake模拟对外部世界的HTTP调用,例如。

(with-fake-routes {
"http://external.api" (fn [request] {:status 500 :headers {} :body "Exception"}
  (is (= 500
       (:status
          (some-function-calling-http-get arg))))))