aboutsummaryrefslogtreecommitdiff
path: root/src/clojure
diff options
context:
space:
mode:
Diffstat (limited to 'src/clojure')
-rw-r--r--src/clojure/contrib/test_is.clj116
-rw-r--r--src/clojure/contrib/test_is/test_fixtures.clj42
2 files changed, 145 insertions, 13 deletions
diff --git a/src/clojure/contrib/test_is.clj b/src/clojure/contrib/test_is.clj
index 23bcae24..5c36fe05 100644
--- a/src/clojure/contrib/test_is.clj
+++ b/src/clojure/contrib/test_is.clj
@@ -1,7 +1,7 @@
;;; test_is.clj: test framework for Clojure
;; by Stuart Sierra, http://stuartsierra.com/
-;; January 21, 2009
+;; March 28, 2009
;; Thanks to Chas Emerick, Allen Rohner, and Stuart Halloway for
;; contributions and suggestions.
@@ -164,6 +164,41 @@
;;
;;
;;
+ ;; FIXTURES (new)
+ ;;
+ ;; 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.
+ )
+
+ ;; Fixtures are attached to namespaces in one of two ways. "each"
+ ;; fixtures are run repeatedly, once for each test function created
+ ;; with "deftest" or "with-test". "each" fixtures are useful for
+ ;; establishing a consistent before/after state for each test, like
+ ;; clearing out database tables.
+ ;;
+ ;; "each" fixtures can be attached to the current namespace like this:
+ (use-fixtures :each fixture1 fixture2 ...)
+ ;; The fixture1, fixture2 are just functions like the example above.
+ ;; They can also be anonymous functions, like this:
+ (use-fixtures :each (fn [f] setup... (f) cleanup...))
+ ;;
+ ;; The other kind of fixture, 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 ...)
+ ;;
+ ;;
+ ;;
;; EXTENDING TEST-IS (ADVANCED)
;;
;; You can extend the behavior of the "is" macro by defining new
@@ -436,16 +471,30 @@
Example: (is (= 4 (+ 2 2)) \"Two plus two should be 4\")
- Special form (is (thrown? c body)) checks that an instance of c is
- thrown from body, fails if not; then returns the thing thrown."
+ Special forms:
+
+ (is (thrown? c body)) checks that an instance of c is thrown from
+ body, fails if not; then returns the thing thrown.
+
+ (is (thrown-with-msg? c re body)) checks that an instance of c is
+ thrown AND that the message on the exception matches (with
+ re-matches) the regular expression re."
([form] `(is ~form nil))
([form msg] `(try-expr ~msg ~form)))
(defmacro are
- "Experimental. May be removed in the future.
- Checks multiple assertions with a template expression.
- Example: (are (= _1 _2) 2 (+ 1 1), 4 (+ 2 2))
- See clojure.contrib.template for documentation of templates."
+ "Checks multiple assertions with a template expression.
+ See clojure.contrib.template/do-template for an explanation of
+ templates.
+
+ Example: (are (= _1 _2)
+ 2 (+ 1 1)
+ 4 (* 2 2))
+ Expands to:
+ (do (is (= 2 (+ 1 1)))
+ (is (= 4 (* 2 2))))
+
+ Note: This breaks some reporting features, such as line numbers."
[expr & args]
`(temp/do-template (is ~expr) ~@args))
@@ -508,6 +557,42 @@
+;;; DEFINING FIXTURES
+
+(defn- add-ns-meta
+ "Adds elements in coll to the current namespace metadata as the
+ value of key."
+ [key coll]
+ (alter-meta! *ns* assoc key (concat (key (meta *ns*)) coll)))
+
+(defmulti use-fixtures (fn [fixture-type & args] fixture-type))
+
+(defmethod use-fixtures :each [fixture-type & args]
+ (add-ns-meta ::each-fixtures args))
+
+(defmethod use-fixtures :once [fixture-type & args]
+ (add-ns-meta ::once-fixtures args))
+
+(defn- default-fixture
+ "The default, empty, fixture function. Just calls its argument."
+ [f]
+ (f))
+
+(defn compose-fixtures
+ "Composes two fixture functions, creating a new fixture function
+ that combines their behavior."
+ [f1 f2]
+ (fn [g] (f1 (fn [] (f2 g)))))
+
+(defn join-fixtures
+ "Composes a collection of fixtures, in order. Always returns a valid
+ fixture function, even if the collection is empty."
+ [fixtures]
+ (reduce compose-fixtures default-fixture fixtures))
+
+
+
+
;;; RUNNING TESTS: LOW-LEVEL FUNCTIONS
(defn test-var
@@ -518,15 +603,20 @@
(binding [*testing-vars* (conj *testing-vars* v)]
(inc-report-counter :test)
(try (t)
- (catch Throwable e
- (report :error "Uncaught exception, not in assertion."
- nil e))))))
+ (catch Throwable e
+ (report :error "Uncaught exception, not in assertion."
+ nil e))))))
(defn test-all-vars
- "Calls test-var on every var interned in the namespace."
+ "Calls test-var on every var interned in the namespace, with fixtures."
[ns]
- (doseq [v (vals (ns-interns ns))]
- (test-var v)))
+ (let [once-fixture-fn (join-fixtures (::once-fixtures (meta ns)))
+ each-fixture-fn (join-fixtures (::each-fixtures (meta ns)))]
+ (once-fixture-fn
+ (fn []
+ (doseq [v (vals (ns-interns ns))]
+ (when (:test (meta v))
+ (each-fixture-fn (fn [] (test-var v)))))))))
(defn test-ns
"If the namespace defines a function named test-ns-hook, calls that.
diff --git a/src/clojure/contrib/test_is/test_fixtures.clj b/src/clojure/contrib/test_is/test_fixtures.clj
new file mode 100644
index 00000000..a583f5a5
--- /dev/null
+++ b/src/clojure/contrib/test_is/test_fixtures.clj
@@ -0,0 +1,42 @@
+;;; test_is/test_fixtures.clj: unit tests for fixtures in test_is.clj
+
+;; by Stuart Sierra, http://stuartsierra.com/
+;; March 28, 2009
+
+;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use
+;; and distribution terms for this software are covered by the Eclipse
+;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+;; which can be found in the file epl-v10.html at the root of this
+;; distribution. By using this software in any fashion, you are
+;; agreeing to be bound by the terms of this license. You must not
+;; remove this notice, or any other, from this software.
+
+
+(ns clojure.contrib.test-is.test-fixtures
+ (:use clojure.contrib.test-is))
+
+(declare *a* *b* *c* *d*)
+
+(defn fixture-a [f]
+ (binding [*a* 3] (f)))
+
+(defn fixture-b [f]
+ (binding [*b* 5] (f)))
+
+(defn fixture-c [f]
+ (binding [*c* 7] (f)))
+
+(defn fixture-d [f]
+ (binding [*d* 11] (f)))
+
+(use-fixtures :once fixture-a fixture-b)
+
+(use-fixtures :each fixture-c fixture-d)
+
+(deftest can-use-once-fixtures
+ (is (= 3 *a*))
+ (is (= 5 *b*)))
+
+(deftest can-use-each-fixtures
+ (is (= 7 *c*))
+ (is (= 11 *d*)))