2017-02-26 68 views
0

midje框架內測試的process-async函數產生不一致的結果。大多數情況下,它按照預期進行檢查,但時常會在初始狀態("")中顯示out.json。我在檢查前依靠async-blocker函數等待process-async測試chan處理函數時結果不一致

我的方法有什麼問題?

(require '[[test-with-files.core :refer [with-files public-dir]]) 

(defn async-blocker [fun & args] 
    (let [chan-test (chan)] 
    (go (>! chan-test (apply fun args))) 
    (<!! chan-test))) 

(defn process-async 
    [channel func] 
    (go-loop [] 
    (when-let [response (<! channel)] 
     (func response) 
     (recur)))) 

(with-files [["/out.json" ""]] 
    (facts "About `process-async" 
      (let [channel (chan) 
       file (io/resource (str public-dir "/out.json")) 
       write #(spit file (str % "\n") :append true)] 
      (doseq [m ["m1" "m2"]] (>!! channel m)) 
      (async-blocker process-async channel write) 
      (clojure.string/split-lines (slurp file)) => (just ["m1" "m2"] :in-any-order) 
      ) 
      ) 
    ) 

回答

1

的問題是,立即用process-async返回「[...]將接收體的結果,當完成 的信道」(因爲go-loop(go (loop ...))go返回只是語法糖立即)。

這意味着,在async-blocker阻擋<!!將具有值幾乎立即並且其中從process-asyncasync-blockergo塊得到執行是未確定的訂單。可能大多數情況下,process-async中的塊首先執行是因爲它是首先創建的,但在併發上下文中這不是很大的保證。

根據<!!的文檔「如果關閉,將返回零,如果沒有任何可用,將會阻止。」這意味着,如果你可以假設的(apply fun args)返回值是go返回的通道,你應該能夠通過下列方式使用<!!阻止:

(defn async-blocker [fun & args] 
    (<!! (apply fun args))) 

這將解除一旦有一個值在通道中(即來自go塊的返回值)。

還有其他選項可以等待另一個go塊的結果。例如,當fun中創建的go塊終止時,您可以提供原始chan-test作爲fun的參數,然後put值爲chan-test。但是我認爲,鑑於您所展示的代碼,其他方法可能會不必要地更復雜。