Skip to content


test-expect Contribution

test-expect is a expectation mocking framework for Clojure.  It is very easy to use and it hooks the result reporting into test-is, the standard Clojure xUnit testing framework that is part of Clojure Contrib (Now clojure.test).  This post is not a test-expect tutorial, but about a minor suggestion I made to Matt Clark, the author of test-expect.

Before I explain the suggestion I made, it is useful to walk through a simple example.

(defn awesome [a b c] a)
(defn what-is [] (awesome 1 2 3))
 
(deftest should-be-awesome
  (expect [awesome (has-args [#(= 1 %) #(= 2 %) #(= 3 %)])] (what-is)))

what-is calls awesome function internally.  We don’t care about what awesome function does, but we need to ensure that it does get called inside what-is with expected arguments passed to it.  The vector after has-args contains functions does exactly that.  Let’s say you accidentally deleted a parameter to awesome function call witin what-is:

(defn awesome [a b c] a)
(defn what-is [] (awesome 1 2))
 
(deftest should-be-awesome
  (expect [awesome (has-args [#(= 1 %)#(= 2 %) #(= 3 %)])] (what-is)))

If you run the test above you should see the following result:

FAIL in (should-be-awesome) (NO_SOURCE_FILE:11)
Unexpected number of arguments. Function name: awesome
expected: 3
actual: 2

The test failed because test-expect internally noticed the argument count is different, so it couldn’t verify all the arguments expected. Let’s say you decided to refactor awesome function to take one less parameter, and you forgot to update all the calling locations.

(defn awesome [a b] a)
(defn what-is [] (awesome 1 2 3))
 
(deftest should-be-awesome
  (expect [awesome (has-args [#(= 1 %) #(= 2 %) #(= 3 %)])] (what-is)))

Ran 1 tests containing 0 assertions.
0 failures, 0 errors

No matter how many times you run your test, nothing will fail.  test-expect only checks if the calling function (what-is) is calling the mocked function with same number of parameters.  It doesn’t actually check with the original awesome function to see how many arguments it is actually expecting.  This is very annoying because you might not know there is a problem until run-time.

It would be nice if test-expect verified that the REAL function has the correct number of parameters. This is a fairly common problem in mock frameworks in dynamic languages. Lucky this functionality is very simple to implement in Clojure.  Every function definition is attached with meta data such as function name, namespace, and expected arguments, etc… For example:

user=>; (meta (resolve ‘awesome))
{:ns #<;Namespace user>;, :name awesome, :file “NO_SOURCE_PATH”, :line 7, :arglists ([a b])}

meta returns a map which contains arguments of the function via :arglists key.  You get the idea.

Originally I submitted a patch to Matt Clark which provided an implementation to fix the problem I described above. Since then Matt has added this feature to test-expect with better error reporting than my original implementation.

Thanks Matt!

Posted in Clojure, Functional Programming.

0 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

Some HTML is OK

(required)

(required, but never shared)

or, reply to this post via trackback.