2014-05-21 26 views
0

我有一個環形處理程序,它使用幾個函數來構建響應。如果這些函數中的任何一個拋出異常,應該被捕獲,以便在返回500之前寫入自定義響應體。我正在爲處理程序編寫單元測試,並且要確保拋出的異常通過這些功能中的任何一個將如上所述進行處理。我的直覺是使用with-redefs一個doseq內:在doseq中使用with-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"))))) 

當然,考慮到with-redefs想改變瓦爾根綁定,它是治療f爲標誌。有沒有辦法讓它重新綁定f所指的var?我懷疑我需要一個宏來完成這個任務,但我希望有人能夠提出一個聰明的解決方案。

回答

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)))))) 
+0

我真的應該養成在問這些問題之前閱讀Clojure源代碼的習慣!由於Clojure的大部分都是在Clojure中實現的,所以實際上可以理解。當然,Googleable有這些問題和答案基本上是Stack Overflow的存在理由。 :) –

+0

@JoshGlover如果你想添加一個答案,請添加一個你自己的答案,而不是編輯一些我從未對我的答案說過的東西。 – amalloy

+0

對不起。考慮到它使用了你的代碼,我認爲它適合你的答案。我不確定是否要添加新的答案,將其添加爲我的問題的更新,或者是什麼。無論如何,如果這是最合適的做法,我會將其添加爲新的答案。再次抱歉! –

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