Clojure 在doseq中与redefs一起使用

Clojure 在doseq中与redefs一起使用,clojure,mocking,Clojure,Mocking,我有一个环处理程序,它使用几个函数来构建响应。如果这些函数中的任何一个抛出异常,则应捕获该异常,以便在返回500之前编写自定义响应正文 我正在为处理程序编写单元测试,我希望确保上述任何函数引发的异常都能得到处理。我的本能是在doseq中使用redefs: (doseq [f [ns1/fn1 ns1/fn2 ns2/fn1]] (with-redefs [f (fn [& args] (throw (RuntimeException. "fail!"))] (let [res

我有一个环处理程序,它使用几个函数来构建响应。如果这些函数中的任何一个抛出异常,则应捕获该异常,以便在返回500之前编写自定义响应正文

我正在为处理程序编写单元测试,我希望确保上述任何函数引发的异常都能得到处理。我的本能是在
doseq
中使用redefs:

(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")))))

当然,考虑到使用redefs的
想要更改vars的根绑定,它将
f
视为一个符号。有没有办法让它重新绑定
f
所指的var?我想我需要一个宏来完成这一点,但我希望有人能想出一个聪明的解决方案。

使用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))))))
下面是我编写的用于测试的实用函数:

(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)))))))

在问这些问题之前,我真的应该养成阅读Clojure资料的习惯!由于大多数Clojure都是在Clojure中实现的,因此实际上可以理解。当然,这些问题和答案基本上是存在堆栈溢出的理由@如果你想添加一个答案,请添加一个你自己的答案,而不是编辑一堆我从来没有在我的答案中说过的东西。很抱歉。我认为它很适合你的答案,因为它使用了你的代码。我真的不确定是否要添加一个新的答案,是否要添加它作为我问题的更新,或者是什么。无论如何,如果这是最合适的做法,我会把它作为一个新的答案添加进去。再次抱歉!