2017-02-26 11 views
0

midje 프레임 워크 내에서 테스트 된 process-async 함수가 일치하지 않는 결과를 생성합니다. 대개의 경우 예상대로 검사하지만 가끔씩 out.json이 초기 상태 ("")로 읽습니다. 나는 확인하기 전에 process-async을 기다리는 async-blocker 함수에 의존한다.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-blocker에서 go 블록 미결정 인 모두 실행되는 순서를 의미합니다. 대부분의 경우 process-async의 블록이 먼저 생성되기 때문에 먼저 실행되지만 대부분 동시 컨텍스트에서는 보장되지 않습니다.

<!!에 대한 설명서에 따르면 "닫힌 경우 nil을 반환합니다. 사용할 수없는 경우 차단합니다."이 당신이 (apply fun args)의 반환 값이 go에 의해 리턴 채널이라고 가정 할 수 있다면, 당신은 다음과 같은 방법으로 <!!를 사용하여 차단할 수 있어야한다는 의미

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

이 해제됩니다 한 번 값이있다 채널에서 (즉, go 블록의 반환 값).

다른 go 블록의 결과를 기다리는 다른 옵션이 있습니다. 예를 들어 fun에 대한 인수로 원래 chan-test을 제공 한 다음 go 블록이 fun에서 생성 될 때 chan-test의 값이 put 인 경우이 값을 종료 할 수 있습니다. 하지만 여러분이 보여준 코드를 보면, 다른 접근 방식이 불필요하게 더 복잡 할 수도 있습니다.