Fact: A unit testing library

90 views
Skip to first unread message

James Reeves

unread,
Nov 9, 2008, 12:38:09 PM11/9/08
to Clojure
Hi folks,

I've put together a unit testing library that borrows ideas from
Ruby's RSpec and Haskell's Quickcheck. In Fact, you define a series of
facts that are verified by predicates. These predicates are tested
many times with sequences of data.

A "fact" takes the form:

(fact description
[symbol sequence
symbol sequence
...]
predicate-expression)

Each item in the sequence is assigned to a symbol, and the predicate
expression evaluated with that data. Sequences are cut down to a
maximum length, so you can specify an infinite sequence if you want,
and it'll just use the first *max-amount* values. The sequences may
also be different lengths; in which case the smaller sequences are
repeated via the cycle function up to the length of the largest
sequence.

A small example:

(fact "The length of a concatenated list is equal to the length of its
parts"
[xs (rand-seqs rand-ints)
ys (rand-seqs rand-ints)]
(= (count (concat xs ys))
(+ (count xs) (count ys))))

In the above example, the rand-seqs and rand-ints functions are used
to generate some random sequences for test data. Generator functions
seem a better fit for a dynamically typed language like Clojure,
rather than generating a sequence of test data based on type. In
addition, you don't have to use randomly generated test data: it works
just as well with a static collection of manually chosen data.

Like RSpec, you can also omit the test itself, so that you can fill it
in at a later date:

(fact "Sentient alien life exists")

These unverified facts are marked as "pending", and will be marked as
such on the test output:

- The length of a concatenated list is equal to the length of its
parts
- Sentient alien life exists (pending)

To actually run the tests:

(print-results (verify-facts namespace))

This verifies the facts present in a namespace, and then prints them
out to the screen. This decoupling of test results and displaying the
results means that HTML and Swing interfaces can easily be added in
future.

The Fact unit testing library is available on github:

http://github.com/weavejester/fact

If you want a real example of Fact, I've written some facts already to
test my web framework, Compojure:

http://github.com/weavejester/compojure/tree/master/test/compojure/html/html.clj

Fact may not be applicable to all situations, and it probably works
best with purely functional code. I think Fact is sufficiently
different to the test-is library in clojure.contrib to warrant its
creation, but I'll need to write a lot more tests with it before I'm
completely convinced the approach I've taken is a good one.

I'd be interested in hearing any criticisms or queries about the
library.

- James
Reply all
Reply to author
Forward
0 new messages