Skip to content

Variant prerequisite arrows

Brian Marick edited this page Apr 17, 2015 · 3 revisions

Prerequisites can return a different value for each call, or throw an exception.

Streaming values from impure prerequisites

Most functions in Clojure programs are "pure": no matter how many times, or when, you call them, they always return the same result. But that's not always true. Consider the rand function, which (probably) returns a new random number after each call.

Now suppose you're testing a function, converger, that calls (rand 0.1) n times and returns the average value. A simple test would be that (converger 2) should return 0.2 if rand first produces 0.1, then again produces 0.3. But to write that test, you need some way to describe rand returning different values on successive calls. That's done with the =streams=> arrow:

(fact 
  (converger 2) => (roughly 0.2)
  (provided
    (rand 1.0) =streams=> [0.1 0.3]))

In this particular case, it might be useful to document that rand should be called exactly two times:

(fact 
  (converger 2) => (roughly 0.2)
  (provided
    (rand 1.0) =streams=> [0.1 0.3] :times 2))

You can also use lazy sequences on the right-hand side of =streams=>. The following streams as many non-negative integers as needed by a caller of provider:

(fact
  ...
  (provided
    (provider) =streams=> (range) ))

Prerequisites that throw exceptions

You can ask that a prerequisite throw an exception when it's called:

(unfinished f)

(defn counter [n]
  (try
    (f n)
  (catch Exception ex
    0)))
      
(fact
  (counter 4) => 0
  (provided
    (f 4) =throws=> (NullPointerException.)))

Testing functions that consume streams of values and must also handle exceptions

Consider a function that sends a stream of requests to the network. For each request, it can get back either a value or an exception. It must handle both. How do you test it?

See the documentation test.

Clone this wiki locally