Question

How do I test a higher-order function in Clojure ?

I can always test a function that accepts a value and then check returned value against the expected one.

How do I do that with a higher order function ?

Or we generally avoid doing so ?

Was it helpful?

Solution

This is a good question. To be more precise about the issue:

Higher-order functions "take or produce other functions as arguments or results". So there's two cases:

  1. functions that take functions. Examples: map, reduce, filter. These aren't too hard to test; just supply all the parameters like you would to a normal function.

  2. functions that return functions. Examples: (fn [x] (fn [y] (+ x y))), (partial filter #(> % 1)). These are difficult to test because we can't directly compare the equality of functions (search for intensional and extensional equality for a thorough discussion).

    It should be obvious that simply not testing is not a very good strategy. So why not take the Haskell view that partially applied functions are essentially the same as functions that return functions -- in other words, pass enough parameters to the returned function to get a result that you can test for equality.

    Just be careful to watch out for coupling in your tests -- make sure that your test cases are actually testing the specification of the higher-order function, not just the function that it returns.

OTHER TIPS

Higher order functions still return results so you can still check it.

For example, if you wanted to test map, think about what it's supposed to do: It is supposed to get a function and a collection as arguments, apply said function to every item in the collection, returning a new collection of the results.

So a simple way of testing that would be:

(is (= [1 2 3 4] (map inc [0 1 2 3]))

The same principle applies if you're testing a higher-order function that is the result of another function: you simply test it returns what's supposed to, after calling the function that returns it:

(defn adder [n]
  (fn [x]
    (+ x n)))

(is (= ((adder 10) 5) 15)) 

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top