ClojureCheck is back.
It brings specification based testing to Clojure and integrates
(almost) seamless with `clojure.test`

. So what does specification
based testing mean and how does it help you?

*ClojureCheck* is one of my oldest Clojure projects. It started
as *ClojureTAP* -- a testing library producing TAP output. Later on
I started to port *QuickCheck*
to Clojure. And hence renamed it. However, I never got really far
and things stalled.

I feel very sad about this. It's the best documented Clojure project
I ever did and it brings up memories from times where todays `require`

system everyone complains about didn't even exist. So for quite some
time now, I had the urge to return *ClojureCheck*. I just didn't want
to let it rot further.

Before I started with the work I had to decide where to hook into.
Originally *ClojureCheck* was developed more or less in parallel to
`clojure.contrib.test-is`

(now: `clojure.test`

). So it basically
contains a similar machinery. However, `clojure.test`

is now the
de-facto standard being included in Clojure itself. So there is no
reason to do things twice and it hooking into `clojure.test`

is a
no-brainer. (Very sad: a lot of nice work gets nuked.)

I also did some more research. I based my original approach too much
on *QuickCheck*. But this gives raise to some problems. In particular
Haskell has one more dimension of information: the type system. So you
can have one function – `arbitrary`

– which does the right thing
depending on the return type you declare. In Clojure this type of
dispatch does not really fly.

Tom Moertel's
*LectroTest* is
written in Perl which is similar to Clojure in terms of dynamism.
I took *LectroTest* as a source of inspiration for the port to Clojure.

So after this rather long introduction: What **is** *ClojureCheck*?

*ClojureCheck* provides facilities to easily generate random test data,
which are then used to „prove“ certain properties of the code under
test. One can eg. generate test data based on a specification. Tom
Moertel does this for email addresses in his talk on *LectroTest*.

Let's use another example from *LectroTest*: `angular-diff`

.

```
(ns our.angular.diff
(:use clojure.test)
(:require [clojurecheck.core :as cc]))
(defn angular-diff
[a b]
(-> (- a b) Math/abs (mod 180)))
```

`angular-diff`

returns the smallest angle between two given angles
`a`

and `b`

. So let's write some tests.

```
(deftest angular-diff-test
; Identical angles should be zero
(are [a b r] (= (angular-diff a b) r)
0 0 0
90 90 0)
; Order of angles shouldn't matter
(are [a b r] (= (angular-diff a b) r)
0 45 45
45 0 45
(is (= (angular-diff 0 270) 90)
"Should return the smallest angle")
(let [a (* 360 2)
b (* 360 4)]
(is (= (angular-diff a (+ b 23)) 23)
"multiples of 360 degrees shouldn't matter"))))
```

And fire:

```
our.angular.diff=> (run-tests)
Testing our.angular.diff
Ran 1 tests containing 4 assertions.
0 failures, 0 errors.
{:type :summary, :test 1, :pass 4, :fail 0, :error 0}
```

Yeah! The world is good!

Is it? Let's apply *ClojureCheck* to our test problem. We want to
generate the problems. So as Tom Moertel says in his talk: we need
needles and an easy way to spot them.

We guess some arbitrary angle `a`

. Now just taking a second angle
`b`

wouldn't help as very much. So we have somehow to work our way
backwards: from the solution to the input.

So next we guess our result: `diff`

. When we feed `angular-diff`

with `a`

and `(+ a diff)`

the expected result is `diff`

. However
adding multiples of 360° don't change things. So we guess a
winding count `n`

and also add it. So whenever `(angular-diff
a (+ a (* n 360) diff))`≠`

(Math/abs diff)` we found our needle!

So let's see how we can cast this in code.

```
(deftest angular-diff-property
(cc/property "angular diff returns the smallest angle between a and b"
[a (cc/int)
n (cc/int)
diff (cc/int :lower -180 :upper 180)]
(let [b (+ a (* n 360) diff)]
(is (= (angular-diff a b) (Math/abs diff))))))
```

And now let's run our test:

```
our.angular.diff=> (run-tests)
Testing our.angular.diff
FAIL in (angular-diff-property) (core.clj:305)
falsified 'angular diff returns the smallest angle between a and b' in 3 attempts
inputs where:
a = 1
n = -1
diff = 1
failed assertions where:
expected: (= (angular-diff a b) (Math/abs diff))
actual: (not (= 179 1))
Ran 2 tests containing 5 assertions.
1 failures, 0 errors.
{:type :summary, :test 2, :pass 4, :fail 1, :error 0}
```

Dang! :( The world is bad.

But we shouldn't think like this. The world is not bad! We are just
too stupid. We should be happy about the failing test, because it tells
us, that we did a mistake in our code. And a mistake is always an occasion
to learn. *(Oh, dear. The QA guy shines through…)*

So to fix our function we have to adapt for angles where the difference is greater than 180°.

```
(defn angular-diff
[a b]
(let [diff (-> (- a b) Math/abs (mod 360))]
(if (> diff 180) (- 360 diff) diff)))
```

Now a test run should look like this:

```
our.angular.diff=> (run-tests)
Testing our.angular.diff
Ran 2 tests containing 5 assertions.
0 failures, 0 errors.
{:type :summary, :test 2, :pass 5, :fail 0, :error 0}
```

Testing systems with random input **can** help. It depends on how you
do it. In particular stimulating the system with random input of a
pre-defined structure can help finding edge cases hidden deep in the
logic.

For unit testing it *can* help to find blind spots in the input coverage.
But with carefully designed tests there might not be any improvements at
all.

So in the end: YMMV.

Published by Meikel Brandmeyer on .

I'm a long-time Clojure user and the developer of several open source projects mostly involving Clojure. I try to actively contribute to the Clojure community.

My most active projects are at the moment VimClojure, Clojuresque and ClojureCheck.

- … type hints?
- … some?
- … argument order?
- … version numbers?
- … comments?
- … bound-fn?
- … ::keywords?
- … -> and ->>?
- … with-open?

Copyright © 2009-2014 All Right Reserved. Meikel Brandmeyer