I've been working on a small library to assert that functions are
called during a unit test.
The syntax looks like:
(calls [[user/foo :times 2 :returns 3]
[user/bar :returns 42]]
(fn-being-tested))
This will assert that foo is called exactly twice, and bar is called
exactly once inside the block. I plan to add support for asserting
that the functions are called with the right arguments.
Comments appreciated, especially about my use of macros, and the
syntax.
(ns clojure.contrib.expectation
(:require [clojure.contrib.test-is :as test]))
(defstruct expectation-hash :called :failed :times)
(defn expect-obj [[var & args]]
(let [opts (apply hash-map args)
state (ref (struct-map expectation-hash :name var :called
0 :failed [] :times (get args :times 1)))]
{:fn (fn [& _]
(dosync
(alter state assoc :called (inc (@state :called))))
(opts :returns))
:state state}))
(defn- validate-expectation
"checks that the expectation was met. Returns true on success"
[expt]
(let [expected-calls (@(expt :state) :times)
actual-calls (@(expt :state) :called)]
(if (= expected-calls actual-calls)
(do
(test/is true (str (@(expt :state) :name) "was called correctly"))
true)
(test/failure (@(expt :state) :name) (str " expected " expected-
calls " actually called " actual-calls " times")))))
(defmacro calls [args & body]
"creates a stub function and asserts the fn was called the correct
number of times
(calls [[user/foo :times 2 :returns 42]
[user/bar :times 1 :returns 3]]
(user/foo x y z)
(user/bar z)"
(let [quote-name (fn [sym] `(var ~sym))
get-name (fn [expt] (first expt))
names (into [] (map (comp quote-name get-name) args))]
`(let [expect-opts# (map rest ~args)
expectations# (map (fn [name# arglist#] (expect-obj (cons name#
arglist#))) ~names expect-opts#)
fns# (map :fn expectations#)
thread-bindings# (apply hash-map (interleave ~names fns#))]
(. clojure.lang.Var (pushThreadBindings thread-bindings#))
(try
[EMAIL PROTECTED]
(finally
(. clojure.lang.Var (popThreadBindings))))
(every? validate-expectation expectations#))))
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---