How do I unit test clojure.core.async go macros?

前端 未结 3 1594
自闭症患者
自闭症患者 2021-02-13 09:27

I\'m trying to write unit tests when using core.async go macros. Writing the test naively, as follows, appears that the code inside the go blocks doesn\'t get executed.

3条回答
  •  北荒
    北荒 (楼主)
    2021-02-13 09:52

    Tests are executed synchronously, so if you go async the test-runner won't. In Clojure you need to block the test runner via , in ClojureScript you have to return an async test object. This is a generic helper function I use in all my async CLJC tests:

    (defn test-async
      "Asynchronous test awaiting ch to produce a value or close."
      [ch]
      #?(:clj
         (

    Your test using it, CLJC compatible and looking way less "hacky":

    (deftest test1
      (let [ch (chan)]
        (go (>! ch "Hello"))
        (test-async
          (go (is (= "Hello" (

    It is good practice to assert that the test unblocks, especially during test driven development where you want to avoid locking your test runner. Also, locking is a common cause of failure in async programming, so testing against it is highly reasonable.

    To do that I wrote a helper similar to your timeout thing:

    (defn test-within
      "Asserts that ch does not close or produce a value within ms. Returns a
      channel from which the value can be taken."
      [ms ch]
      (go (let [t (timeout ms)
                [v ch] (alts! [ch t])]
            (is (not= ch t)
                (str "Test should have finished within " ms "ms."))
            v)))
    

    You can use it to write your test like:

    (deftest test1
      (let [ch (chan)]
        (go (>! ch "Hello"))
        (test-async
          (test-within 1000
            (go (is (= "Hello" (

提交回复
热议问题