I thought I’d tested that!

I’ve been spending some time looking at Clojure 1.1, in particular the changes between version 1.0 and 1.1.

The first thing I found was that there is now a test framework contained within the base image. Clojure.test contains a means of defining tests, together with some functions that run all of the tests in a given package.

We can, for example, define a simple function and then define some tests to fix its behaviour.

user> (use ‘clojure.test)
nil
user> (defn my-function [x] (* x 2))
#’user/my-function
user> (deftest test-my-function
    (is (= (my-function 10) 20))
    (is (= (my-function 1) 2)))
#’user/test-my-function
user> (run-tests)

Testing user

Ran 1 tests containing 2 assertions.
0 failures, 0 errors.
{:type :summary, :test 1, :pass 2, :fail 0, :error 0}

If the function gets redefined, it will then be picked up by the tests.

user> (defn my-function [x] (* x 3))
#’user/my-function
user> (run-tests)

Testing user

FAIL in (test-my-function) (NO_SOURCE_FILE:1)
expected: (= (my-function 10) 20)
  actual: (not (= 30 20))

FAIL in (test-my-function) (NO_SOURCE_FILE:1)
expected: (= (my-function 1) 2)
  actual: (not (= 3 2))

Ran 1 tests containing 2 assertions.
2 failures, 0 errors.
{:type :summary, :test 1, :pass 0, :fail 2, :error 0}

There is also the means to set up fixtures, which can be executed around each test or around each batch of tests. For example, we could set up a test that checks the dynamic context.

user> (def *a* 0)
#’user/*a*
user> (def *b* 0)
#’user/*b*
user> (deftest check-context
    (is (= *a* 1))
    (is (= *b* 1)))
#’user/check-context

This fails as we have things now.

user> (run-tests)

Testing user

FAIL in (check-context) (NO_SOURCE_FILE:1)
expected: (= *a* 1)
  actual: (not (= 0 1))

FAIL in (check-context) (NO_SOURCE_FILE:1)
expected: (= *b* 1)
  actual: (not (= 0 1))

Ran 1 tests containing 2 assertions.
2 failures, 0 errors.
{:type :summary, :test 1, :pass 0, :fail 2, :error 0}

We can define fixtures to set up the context in which the test runs. These fixture functions take a function as an argument. They then establish the environment and call the passed in function, and afterwards clean up again. We set the fixtures by using the use-fixtures function.

user> (defn fixture1 [f]
    (binding [*a* 1]
         (f)))
#’user/fixture1
user> (defn fixture2 [f]
    (binding [*b* 1]
         (f)))
#’user/fixture2
user> (use-fixtures :each fixture1 fixture2)
{:clojure.test/each-fixtures (#<user$fixture1__3374 user$fixture1__3374@199f443> #<user$fixture2__3395 user$fixture2__3395@c47498>)}
user> (run-tests)

Testing user

Ran 1 tests containing 2 assertions.
0 failures, 0 errors.
{:type :summary, :test 1, :pass 2, :fail 0, :error 0}

This entry was posted in Computers and Internet. Bookmark the permalink.

Leave a comment