【问题标题】:Inconsistent results when testing a chan processing function测试 chan 处理函数时结果不一致
【发布时间】:2017-02-26 07:32:17
【问题描述】:

midje 框架内测试的process-async 函数产生不一致的结果。大多数情况下,它会按预期进行检查,但有时会在初始状态 ("") 读取 out.json。我依靠async-blocker 函数在检查之前等待process-async

我的方法有什么问题?

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

【问题讨论】:

    标签: unit-testing clojure core.async midje


    【解决方案1】:

    问题是process-async 立即返回 "[...] 一个通道,该通道将在以下情况下接收正文的结果 完成”(因为go-loop 只是(go (loop ...)) 的语法糖,go 立即返回)。

    这意味着 async-blocker 中的阻塞 &lt;!! 将几乎立即具有值,并且来自 process-asyncasync-blockergo 阻塞的执行顺序未确定。可能大部分时间来自process-async 的块首先执行,因为它首先被创建,但这在并发上下文中并不能保证。

    根据&lt;!! 的文档,它 “如果关闭将返回 nil。如果没有可用的将阻塞。” 这意味着如果您可以假设 (apply fun args) 的返回值为go 返回的频道,您应该可以通过以下方式使用&lt;!! 阻止:

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

    一旦通道中有值(即来自go 块的返回值),这将解除阻塞。

    还有其他选项可以等待另一个 go 块的结果。例如,您可以提供原始的 chan-test 作为 fun 的参数,然后在 fun 中创建的 go 块终止时将 put 中的值提供给 chan-test。但我认为,鉴于您展示的代码,其他方法可能会不必要地更加复杂。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-09
      • 2012-02-19
      • 1970-01-01
      • 1970-01-01
      • 2021-06-12
      • 2016-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多