开发者

how to unit test for laziness

I have a function that is supposed to take a lazy seq and return an unrealized lazy seq. Now I want to write a unit test (in test开发者_Go百科-is btw) to make sure that the result is an unrealized lazy sequence.


user=> (instance? clojure.lang.LazySeq (map + [1 2 3 4] [1 2 3 4]))
true

If you have a lot of things to test, maybe this would simplify it:

(defmacro is-lazy? [x] `(is (instance? clojure.lang.LazySeq ~x)))

user=> (is-lazy? 1)

FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:7)
expected: (clojure.core/instance? clojure.lang.LazySeq 1)
  actual: (not (clojure.core/instance? clojure.lang.LazySeq 1))
false
user=> (is-lazy? (map + [1 2 3 4] [1 2 3 4]))
true

As of Clojure 1.3 there is also the realized? function: "Returns true if a value has been produced for a promise, delay, future or lazy sequence."


Use a function with a side effect (say, writing to a ref) as the sequence generator function in your test case. If the side effect never happens, it means the sequence remains unrealized... as soon as the sequence is realized, the function will be called.

First, set it up like this:

(def effect-count (ref 0))

(defn test-fn [x]
    (do
        (dosync (alter effect-count inc))
        x))

Then, run your function. I'll just use map, here:

(def result (map test-fn (range 1 10)))

Test if test-fn ever ran:

(if (= 0 @effect-count) 
    (println "Test passed!")
    (println "Test failed!"))

Since we know map is lazy, it should always work at this point. Now, force evaluation of the sequence:

(dorun result)

And check the value of effect-count again. This time, we DO expect the side effect to have triggered. And, it is so...

user=>@effect-count
9
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜