David Williams
David Williams

Reputation: 8654

Clojure: How To use-fixtures in Testing

I am writing some unit tests that interact with a database. For this reason it is useful to have a setup and a teardown method in my unit test to create and then drop the table. However there are no docs :O on the use-fixtures method.

Here is what i need to do:

 (setup-tests)
 (run-tests)
 (teardown-tests)

I am not interested currently in running a setup and teardown before and after each test, but once before a group of tests and once after. How do you do this?

Upvotes: 17

Views: 10909

Answers (2)

Dave Liepmann
Dave Liepmann

Reputation: 1369

Per the API for clojure.test:

Fixtures allow you to run code before and after tests, to set up the context in which tests should be run.

A fixture is just a function that calls another function passed as an argument. It looks like this:

(defn my-fixture [f]    
  ;; Perform setup, establish bindings, whatever.   
  (f) ;; Then call the function we were passed.    
  ;; Tear-down / clean-up code here.  
)

There are "each" fixtures for set-up and tear-down around individual tests, but you wrote that you want what "once" fixtures provide:

[A] "once" fixture is only run once, around ALL the tests in the namespace. "once" fixtures are useful for tasks that only need to be performed once, like establishing database connections, or for time-consuming tasks.

Attach "once" fixtures to the current namespace like this:

(use-fixtures :once fixture1 fixture2 ...)

I'd probably write your fixture something like:

(use-fixtures :once (fn [f] 
                      (setup-tests)
                      (f)
                      (teardown-tests)))

Upvotes: 1

Joost Diepenmaat
Joost Diepenmaat

Reputation: 17773

You can't use use-fixtures to provide setup and teardown code for freely defined groups of tests, but you can use :once to provide setup and teardown code for each namespace:

;; my/test/config.clj
(ns my.test.config)

(defn wrap-setup
  [f]
  (println "wrapping setup")
  ;; note that you generally want to run teardown-tests in a try ...
  ;; finally construct, but this is just an example
  (setup-test)
  (f)
  (teardown-test))    


;; my/package_test.clj
(ns my.package-test
  (:use clojure.test
        my.test.config))

(use-fixtures :once wrap-setup) ; wrap-setup around the whole namespace of tests. 
                                ; use :each to wrap around each individual test 
                                ; in this package.

(testing ... )

This approach forces some coupling between setup and teardown code and the packages the tests are in, but generally that's not a huge problem. You can always do your own manual wrapping in testing sections, see for example the bottom half of this blog post.

Upvotes: 25

Related Questions