comparison src/clojure/test.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
comparison
equal deleted inserted replaced
9:35cf337adfcf 10:ef7dbbd6452c
1 ; Copyright (c) Rich Hickey. All rights reserved.
2 ; The use and distribution terms for this software are covered by the
3 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 ; which can be found in the file epl-v10.html at the root of this distribution.
5 ; By using this software in any fashion, you are agreeing to be bound by
6 ; the terms of this license.
7 ; You must not remove this notice, or any other, from this software.
8
9 ;;; test.clj: test framework for Clojure
10
11 ;; by Stuart Sierra
12 ;; March 28, 2009
13
14 ;; Thanks to Chas Emerick, Allen Rohner, and Stuart Halloway for
15 ;; contributions and suggestions.
16
17 (ns
18 ^{:author "Stuart Sierra, with contributions and suggestions by
19 Chas Emerick, Allen Rohner, and Stuart Halloway",
20 :doc "A unit testing framework.
21
22 ASSERTIONS
23
24 The core of the library is the \"is\" macro, which lets you make
25 assertions of any arbitrary expression:
26
27 (is (= 4 (+ 2 2)))
28 (is (instance? Integer 256))
29 (is (.startsWith \"abcde\" \"ab\"))
30
31 You can type an \"is\" expression directly at the REPL, which will
32 print a message if it fails.
33
34 user> (is (= 5 (+ 2 2)))
35
36 FAIL in (:1)
37 expected: (= 5 (+ 2 2))
38 actual: (not (= 5 4))
39 false
40
41 The \"expected:\" line shows you the original expression, and the
42 \"actual:\" shows you what actually happened. In this case, it
43 shows that (+ 2 2) returned 4, which is not = to 5. Finally, the
44 \"false\" on the last line is the value returned from the
45 expression. The \"is\" macro always returns the result of the
46 inner expression.
47
48 There are two special assertions for testing exceptions. The
49 \"(is (thrown? c ...))\" form tests if an exception of class c is
50 thrown:
51
52 (is (thrown? ArithmeticException (/ 1 0)))
53
54 \"(is (thrown-with-msg? c re ...))\" does the same thing and also
55 tests that the message on the exception matches the regular
56 expression re:
57
58 (is (thrown-with-msg? ArithmeticException #\"Divide by zero\"
59 (/ 1 0)))
60
61 DOCUMENTING TESTS
62
63 \"is\" takes an optional second argument, a string describing the
64 assertion. This message will be included in the error report.
65
66 (is (= 5 (+ 2 2)) \"Crazy arithmetic\")
67
68 In addition, you can document groups of assertions with the
69 \"testing\" macro, which takes a string followed by any number of
70 assertions. The string will be included in failure reports.
71 Calls to \"testing\" may be nested, and all of the strings will be
72 joined together with spaces in the final report, in a style
73 similar to RSpec <http://rspec.info/>
74
75 (testing \"Arithmetic\"
76 (testing \"with positive integers\"
77 (is (= 4 (+ 2 2)))
78 (is (= 7 (+ 3 4))))
79 (testing \"with negative integers\"
80 (is (= -4 (+ -2 -2)))
81 (is (= -1 (+ 3 -4)))))
82
83 Note that, unlike RSpec, the \"testing\" macro may only be used
84 INSIDE a \"deftest\" or \"with-test\" form (see below).
85
86
87 DEFINING TESTS
88
89 There are two ways to define tests. The \"with-test\" macro takes
90 a defn or def form as its first argument, followed by any number
91 of assertions. The tests will be stored as metadata on the
92 definition.
93
94 (with-test
95 (defn my-function [x y]
96 (+ x y))
97 (is (= 4 (my-function 2 2)))
98 (is (= 7 (my-function 3 4))))
99
100 As of Clojure SVN rev. 1221, this does not work with defmacro.
101 See http://code.google.com/p/clojure/issues/detail?id=51
102
103 The other way lets you define tests separately from the rest of
104 your code, even in a different namespace:
105
106 (deftest addition
107 (is (= 4 (+ 2 2)))
108 (is (= 7 (+ 3 4))))
109
110 (deftest subtraction
111 (is (= 1 (- 4 3)))
112 (is (= 3 (- 7 4))))
113
114 This creates functions named \"addition\" and \"subtraction\", which
115 can be called like any other function. Therefore, tests can be
116 grouped and composed, in a style similar to the test framework in
117 Peter Seibel's \"Practical Common Lisp\"
118 <http://www.gigamonkeys.com/book/practical-building-a-unit-test-framework.html>
119
120 (deftest arithmetic
121 (addition)
122 (subtraction))
123
124 The names of the nested tests will be joined in a list, like
125 \"(arithmetic addition)\", in failure reports. You can use nested
126 tests to set up a context shared by several tests.
127
128
129 RUNNING TESTS
130
131 Run tests with the function \"(run-tests namespaces...)\":
132
133 (run-tests 'your.namespace 'some.other.namespace)
134
135 If you don't specify any namespaces, the current namespace is
136 used. To run all tests in all namespaces, use \"(run-all-tests)\".
137
138 By default, these functions will search for all tests defined in
139 a namespace and run them in an undefined order. However, if you
140 are composing tests, as in the \"arithmetic\" example above, you
141 probably do not want the \"addition\" and \"subtraction\" tests run
142 separately. In that case, you must define a special function
143 named \"test-ns-hook\" that runs your tests in the correct order:
144
145 (defn test-ns-hook []
146 (arithmetic))
147
148
149 OMITTING TESTS FROM PRODUCTION CODE
150
151 You can bind the variable \"*load-tests*\" to false when loading or
152 compiling code in production. This will prevent any tests from
153 being created by \"with-test\" or \"deftest\".
154
155
156 FIXTURES (new)
157
158 Fixtures allow you to run code before and after tests, to set up
159 the context in which tests should be run.
160
161 A fixture is just a function that calls another function passed as
162 an argument. It looks like this:
163
164 (defn my-fixture [f]
165 Perform setup, establish bindings, whatever.
166 (f) Then call the function we were passed.
167 Tear-down / clean-up code here.
168 )
169
170 Fixtures are attached to namespaces in one of two ways. \"each\"
171 fixtures are run repeatedly, once for each test function created
172 with \"deftest\" or \"with-test\". \"each\" fixtures are useful for
173 establishing a consistent before/after state for each test, like
174 clearing out database tables.
175
176 \"each\" fixtures can be attached to the current namespace like this:
177 (use-fixtures :each fixture1 fixture2 ...)
178 The fixture1, fixture2 are just functions like the example above.
179 They can also be anonymous functions, like this:
180 (use-fixtures :each (fn [f] setup... (f) cleanup...))
181
182 The other kind of fixture, a \"once\" fixture, is only run once,
183 around ALL the tests in the namespace. \"once\" fixtures are useful
184 for tasks that only need to be performed once, like establishing
185 database connections, or for time-consuming tasks.
186
187 Attach \"once\" fixtures to the current namespace like this:
188 (use-fixtures :once fixture1 fixture2 ...)
189
190
191 SAVING TEST OUTPUT TO A FILE
192
193 All the test reporting functions write to the var *test-out*. By
194 default, this is the same as *out*, but you can rebind it to any
195 PrintWriter. For example, it could be a file opened with
196 clojure.java.io/writer.
197
198
199 EXTENDING TEST-IS (ADVANCED)
200
201 You can extend the behavior of the \"is\" macro by defining new
202 methods for the \"assert-expr\" multimethod. These methods are
203 called during expansion of the \"is\" macro, so they should return
204 quoted forms to be evaluated.
205
206 You can plug in your own test-reporting framework by rebinding
207 the \"report\" function: (report event)
208
209 The 'event' argument is a map. It will always have a :type key,
210 whose value will be a keyword signaling the type of event being
211 reported. Standard events with :type value of :pass, :fail, and
212 :error are called when an assertion passes, fails, and throws an
213 exception, respectively. In that case, the event will also have
214 the following keys:
215
216 :expected The form that was expected to be true
217 :actual A form representing what actually occurred
218 :message The string message given as an argument to 'is'
219
220 The \"testing\" strings will be a list in \"*testing-contexts*\", and
221 the vars being tested will be a list in \"*testing-vars*\".
222
223 Your \"report\" function should wrap any printing calls in the
224 \"with-test-out\" macro, which rebinds *out* to the current value
225 of *test-out*.
226
227 For additional event types, see the examples in the code.
228 "}
229 clojure.test
230 (:require [clojure.template :as temp]
231 [clojure.stacktrace :as stack]))
232
233 ;; Nothing is marked "private" here, so you can rebind things to plug
234 ;; in your own testing or reporting frameworks.
235
236
237 ;;; USER-MODIFIABLE GLOBALS
238
239 (defonce
240 ^{:doc "True by default. If set to false, no test functions will
241 be created by deftest, set-test, or with-test. Use this to omit
242 tests when compiling or loading production code."
243 :added "1.1"}
244 *load-tests* true)
245
246 (def
247 ^{:doc "The maximum depth of stack traces to print when an Exception
248 is thrown during a test. Defaults to nil, which means print the
249 complete stack trace."
250 :added "1.1"}
251 *stack-trace-depth* nil)
252
253
254 ;;; GLOBALS USED BY THE REPORTING FUNCTIONS
255
256 (def *report-counters* nil) ; bound to a ref of a map in test-ns
257
258 (def *initial-report-counters* ; used to initialize *report-counters*
259 {:test 0, :pass 0, :fail 0, :error 0})
260
261 (def *testing-vars* (list)) ; bound to hierarchy of vars being tested
262
263 (def *testing-contexts* (list)) ; bound to hierarchy of "testing" strings
264
265 (def *test-out* *out*) ; PrintWriter for test reporting output
266
267 (defmacro with-test-out
268 "Runs body with *out* bound to the value of *test-out*."
269 {:added "1.1"}
270 [& body]
271 `(binding [*out* *test-out*]
272 ~@body))
273
274 ;;; UTILITIES FOR REPORTING FUNCTIONS
275
276 (defn file-position
277 "Returns a vector [filename line-number] for the nth call up the
278 stack.
279
280 Deprecated in 1.2: The information needed for test reporting is
281 now on :file and :line keys in the result map."
282 {:added "1.1"
283 :deprecated "1.2"}
284 [n]
285 (let [^StackTraceElement s (nth (.getStackTrace (new java.lang.Throwable)) n)]
286 [(.getFileName s) (.getLineNumber s)]))
287
288 (defn testing-vars-str
289 "Returns a string representation of the current test. Renders names
290 in *testing-vars* as a list, then the source file and line of
291 current assertion."
292 {:added "1.1"}
293 [m]
294 (let [{:keys [file line]} m]
295 (str
296 ;; Uncomment to include namespace in failure report:
297 ;;(ns-name (:ns (meta (first *testing-vars*)))) "/ "
298 (reverse (map #(:name (meta %)) *testing-vars*))
299 " (" file ":" line ")")))
300
301 (defn testing-contexts-str
302 "Returns a string representation of the current test context. Joins
303 strings in *testing-contexts* with spaces."
304 {:added "1.1"}
305 []
306 (apply str (interpose " " (reverse *testing-contexts*))))
307
308 (defn inc-report-counter
309 "Increments the named counter in *report-counters*, a ref to a map.
310 Does nothing if *report-counters* is nil."
311 {:added "1.1"}
312 [name]
313 (when *report-counters*
314 (dosync (commute *report-counters* assoc name
315 (inc (or (*report-counters* name) 0))))))
316
317 ;;; TEST RESULT REPORTING
318
319 (defmulti
320 ^{:doc "Generic reporting function, may be overridden to plug in
321 different report formats (e.g., TAP, JUnit). Assertions such as
322 'is' call 'report' to indicate results. The argument given to
323 'report' will be a map with a :type key. See the documentation at
324 the top of test_is.clj for more information on the types of
325 arguments for 'report'."
326 :dynamic true
327 :added "1.1"}
328 report :type)
329
330 (defn- file-and-line
331 [exception depth]
332 (let [^StackTraceElement s (nth (.getStackTrace exception) depth)]
333 {:file (.getFileName s) :line (.getLineNumber s)}))
334
335 (defn do-report
336 "Add file and line information to a test result and call report.
337 If you are writing a custom assert-expr method, call this function
338 to pass test results to report."
339 {:added "1.2"}
340 [m]
341 (report
342 (case
343 (:type m)
344 :fail (merge (file-and-line (new java.lang.Throwable) 1) m)
345 :error (merge (file-and-line (:actual m) 0) m)
346 m)))
347
348 (defmethod report :default [m]
349 (with-test-out (prn m)))
350
351 (defmethod report :pass [m]
352 (with-test-out (inc-report-counter :pass)))
353
354 (defmethod report :fail [m]
355 (with-test-out
356 (inc-report-counter :fail)
357 (println "\nFAIL in" (testing-vars-str m))
358 (when (seq *testing-contexts*) (println (testing-contexts-str)))
359 (when-let [message (:message m)] (println message))
360 (println "expected:" (pr-str (:expected m)))
361 (println " actual:" (pr-str (:actual m)))))
362
363 (defmethod report :error [m]
364 (with-test-out
365 (inc-report-counter :error)
366 (println "\nERROR in" (testing-vars-str m))
367 (when (seq *testing-contexts*) (println (testing-contexts-str)))
368 (when-let [message (:message m)] (println message))
369 (println "expected:" (pr-str (:expected m)))
370 (print " actual: ")
371 (let [actual (:actual m)]
372 (if (instance? Throwable actual)
373 (stack/print-cause-trace actual *stack-trace-depth*)
374 (prn actual)))))
375
376 (defmethod report :summary [m]
377 (with-test-out
378 (println "\nRan" (:test m) "tests containing"
379 (+ (:pass m) (:fail m) (:error m)) "assertions.")
380 (println (:fail m) "failures," (:error m) "errors.")))
381
382 (defmethod report :begin-test-ns [m]
383 (with-test-out
384 (println "\nTesting" (ns-name (:ns m)))))
385
386 ;; Ignore these message types:
387 (defmethod report :end-test-ns [m])
388 (defmethod report :begin-test-var [m])
389 (defmethod report :end-test-var [m])
390
391
392
393 ;;; UTILITIES FOR ASSERTIONS
394
395 (defn get-possibly-unbound-var
396 "Like var-get but returns nil if the var is unbound."
397 {:added "1.1"}
398 [v]
399 (try (var-get v)
400 (catch IllegalStateException e
401 nil)))
402
403 (defn function?
404 "Returns true if argument is a function or a symbol that resolves to
405 a function (not a macro)."
406 {:added "1.1"}
407 [x]
408 (if (symbol? x)
409 (when-let [v (resolve x)]
410 (when-let [value (get-possibly-unbound-var v)]
411 (and (fn? value)
412 (not (:macro (meta v))))))
413 (fn? x)))
414
415 (defn assert-predicate
416 "Returns generic assertion code for any functional predicate. The
417 'expected' argument to 'report' will contains the original form, the
418 'actual' argument will contain the form with all its sub-forms
419 evaluated. If the predicate returns false, the 'actual' form will
420 be wrapped in (not...)."
421 {:added "1.1"}
422 [msg form]
423 (let [args (rest form)
424 pred (first form)]
425 `(let [values# (list ~@args)
426 result# (apply ~pred values#)]
427 (if result#
428 (do-report {:type :pass, :message ~msg,
429 :expected '~form, :actual (cons ~pred values#)})
430 (do-report {:type :fail, :message ~msg,
431 :expected '~form, :actual (list '~'not (cons '~pred values#))}))
432 result#)))
433
434 (defn assert-any
435 "Returns generic assertion code for any test, including macros, Java
436 method calls, or isolated symbols."
437 {:added "1.1"}
438 [msg form]
439 `(let [value# ~form]
440 (if value#
441 (do-report {:type :pass, :message ~msg,
442 :expected '~form, :actual value#})
443 (do-report {:type :fail, :message ~msg,
444 :expected '~form, :actual value#}))
445 value#))
446
447
448
449 ;;; ASSERTION METHODS
450
451 ;; You don't call these, but you can add methods to extend the 'is'
452 ;; macro. These define different kinds of tests, based on the first
453 ;; symbol in the test expression.
454
455 (defmulti assert-expr
456 (fn [msg form]
457 (cond
458 (nil? form) :always-fail
459 (seq? form) (first form)
460 :else :default)))
461
462 (defmethod assert-expr :always-fail [msg form]
463 ;; nil test: always fail
464 `(do-report {:type :fail, :message ~msg}))
465
466 (defmethod assert-expr :default [msg form]
467 (if (and (sequential? form) (function? (first form)))
468 (assert-predicate msg form)
469 (assert-any msg form)))
470
471 (defmethod assert-expr 'instance? [msg form]
472 ;; Test if x is an instance of y.
473 `(let [klass# ~(nth form 1)
474 object# ~(nth form 2)]
475 (let [result# (instance? klass# object#)]
476 (if result#
477 (do-report {:type :pass, :message ~msg,
478 :expected '~form, :actual (class object#)})
479 (do-report {:type :fail, :message ~msg,
480 :expected '~form, :actual (class object#)}))
481 result#)))
482
483 (defmethod assert-expr 'thrown? [msg form]
484 ;; (is (thrown? c expr))
485 ;; Asserts that evaluating expr throws an exception of class c.
486 ;; Returns the exception thrown.
487 (let [klass (second form)
488 body (nthnext form 2)]
489 `(try ~@body
490 (do-report {:type :fail, :message ~msg,
491 :expected '~form, :actual nil})
492 (catch ~klass e#
493 (do-report {:type :pass, :message ~msg,
494 :expected '~form, :actual e#})
495 e#))))
496
497 (defmethod assert-expr 'thrown-with-msg? [msg form]
498 ;; (is (thrown-with-msg? c re expr))
499 ;; Asserts that evaluating expr throws an exception of class c.
500 ;; Also asserts that the message string of the exception matches
501 ;; (with re-find) the regular expression re.
502 (let [klass (nth form 1)
503 re (nth form 2)
504 body (nthnext form 3)]
505 `(try ~@body
506 (do-report {:type :fail, :message ~msg, :expected '~form, :actual nil})
507 (catch ~klass e#
508 (let [m# (.getMessage e#)]
509 (if (re-find ~re m#)
510 (do-report {:type :pass, :message ~msg,
511 :expected '~form, :actual e#})
512 (do-report {:type :fail, :message ~msg,
513 :expected '~form, :actual e#})))
514 e#))))
515
516
517 (defmacro try-expr
518 "Used by the 'is' macro to catch unexpected exceptions.
519 You don't call this."
520 {:added "1.1"}
521 [msg form]
522 `(try ~(assert-expr msg form)
523 (catch Throwable t#
524 (do-report {:type :error, :message ~msg,
525 :expected '~form, :actual t#}))))
526
527
528
529 ;;; ASSERTION MACROS
530
531 ;; You use these in your tests.
532
533 (defmacro is
534 "Generic assertion macro. 'form' is any predicate test.
535 'msg' is an optional message to attach to the assertion.
536
537 Example: (is (= 4 (+ 2 2)) \"Two plus two should be 4\")
538
539 Special forms:
540
541 (is (thrown? c body)) checks that an instance of c is thrown from
542 body, fails if not; then returns the thing thrown.
543
544 (is (thrown-with-msg? c re body)) checks that an instance of c is
545 thrown AND that the message on the exception matches (with
546 re-find) the regular expression re."
547 {:added "1.1"}
548 ([form] `(is ~form nil))
549 ([form msg] `(try-expr ~msg ~form)))
550
551 (defmacro are
552 "Checks multiple assertions with a template expression.
553 See clojure.template/do-template for an explanation of
554 templates.
555
556 Example: (are [x y] (= x y)
557 2 (+ 1 1)
558 4 (* 2 2))
559 Expands to:
560 (do (is (= 2 (+ 1 1)))
561 (is (= 4 (* 2 2))))
562
563 Note: This breaks some reporting features, such as line numbers."
564 {:added "1.1"}
565 [argv expr & args]
566 `(temp/do-template ~argv (is ~expr) ~@args))
567
568 (defmacro testing
569 "Adds a new string to the list of testing contexts. May be nested,
570 but must occur inside a test function (deftest)."
571 {:added "1.1"}
572 [string & body]
573 `(binding [*testing-contexts* (conj *testing-contexts* ~string)]
574 ~@body))
575
576
577
578 ;;; DEFINING TESTS
579
580 (defmacro with-test
581 "Takes any definition form (that returns a Var) as the first argument.
582 Remaining body goes in the :test metadata function for that Var.
583
584 When *load-tests* is false, only evaluates the definition, ignoring
585 the tests."
586 {:added "1.1"}
587 [definition & body]
588 (if *load-tests*
589 `(doto ~definition (alter-meta! assoc :test (fn [] ~@body)))
590 definition))
591
592
593 (defmacro deftest
594 "Defines a test function with no arguments. Test functions may call
595 other tests, so tests may be composed. If you compose tests, you
596 should also define a function named test-ns-hook; run-tests will
597 call test-ns-hook instead of testing all vars.
598
599 Note: Actually, the test body goes in the :test metadata on the var,
600 and the real function (the value of the var) calls test-var on
601 itself.
602
603 When *load-tests* is false, deftest is ignored."
604 {:added "1.1"}
605 [name & body]
606 (when *load-tests*
607 `(def ~(vary-meta name assoc :test `(fn [] ~@body))
608 (fn [] (test-var (var ~name))))))
609
610 (defmacro deftest-
611 "Like deftest but creates a private var."
612 {:added "1.1"}
613 [name & body]
614 (when *load-tests*
615 `(def ~(vary-meta name assoc :test `(fn [] ~@body) :private true)
616 (fn [] (test-var (var ~name))))))
617
618
619 (defmacro set-test
620 "Experimental.
621 Sets :test metadata of the named var to a fn with the given body.
622 The var must already exist. Does not modify the value of the var.
623
624 When *load-tests* is false, set-test is ignored."
625 {:added "1.1"}
626 [name & body]
627 (when *load-tests*
628 `(alter-meta! (var ~name) assoc :test (fn [] ~@body))))
629
630
631
632 ;;; DEFINING FIXTURES
633
634 (defn- add-ns-meta
635 "Adds elements in coll to the current namespace metadata as the
636 value of key."
637 {:added "1.1"}
638 [key coll]
639 (alter-meta! *ns* assoc key coll))
640
641 (defmulti use-fixtures
642 "Wrap test runs in a fixture function to perform setup and
643 teardown. Using a fixture-type of :each wraps every test
644 individually, while:once wraps the whole run in a single function."
645 {:added "1.1"}
646 (fn [fixture-type & args] fixture-type))
647
648 (defmethod use-fixtures :each [fixture-type & args]
649 (add-ns-meta ::each-fixtures args))
650
651 (defmethod use-fixtures :once [fixture-type & args]
652 (add-ns-meta ::once-fixtures args))
653
654 (defn- default-fixture
655 "The default, empty, fixture function. Just calls its argument."
656 {:added "1.1"}
657 [f]
658 (f))
659
660 (defn compose-fixtures
661 "Composes two fixture functions, creating a new fixture function
662 that combines their behavior."
663 {:added "1.1"}
664 [f1 f2]
665 (fn [g] (f1 (fn [] (f2 g)))))
666
667 (defn join-fixtures
668 "Composes a collection of fixtures, in order. Always returns a valid
669 fixture function, even if the collection is empty."
670 {:added "1.1"}
671 [fixtures]
672 (reduce compose-fixtures default-fixture fixtures))
673
674
675
676
677 ;;; RUNNING TESTS: LOW-LEVEL FUNCTIONS
678
679 (defn test-var
680 "If v has a function in its :test metadata, calls that function,
681 with *testing-vars* bound to (conj *testing-vars* v)."
682 {:dynamic true, :added "1.1"}
683 [v]
684 (when-let [t (:test (meta v))]
685 (binding [*testing-vars* (conj *testing-vars* v)]
686 (do-report {:type :begin-test-var, :var v})
687 (inc-report-counter :test)
688 (try (t)
689 (catch Throwable e
690 (do-report {:type :error, :message "Uncaught exception, not in assertion."
691 :expected nil, :actual e})))
692 (do-report {:type :end-test-var, :var v}))))
693
694 (defn test-all-vars
695 "Calls test-var on every var interned in the namespace, with fixtures."
696 {:added "1.1"}
697 [ns]
698 (let [once-fixture-fn (join-fixtures (::once-fixtures (meta ns)))
699 each-fixture-fn (join-fixtures (::each-fixtures (meta ns)))]
700 (once-fixture-fn
701 (fn []
702 (doseq [v (vals (ns-interns ns))]
703 (when (:test (meta v))
704 (each-fixture-fn (fn [] (test-var v)))))))))
705
706 (defn test-ns
707 "If the namespace defines a function named test-ns-hook, calls that.
708 Otherwise, calls test-all-vars on the namespace. 'ns' is a
709 namespace object or a symbol.
710
711 Internally binds *report-counters* to a ref initialized to
712 *inital-report-counters*. Returns the final, dereferenced state of
713 *report-counters*."
714 {:added "1.1"}
715 [ns]
716 (binding [*report-counters* (ref *initial-report-counters*)]
717 (let [ns-obj (the-ns ns)]
718 (do-report {:type :begin-test-ns, :ns ns-obj})
719 ;; If the namespace has a test-ns-hook function, call that:
720 (if-let [v (find-var (symbol (str (ns-name ns-obj)) "test-ns-hook"))]
721 ((var-get v))
722 ;; Otherwise, just test every var in the namespace.
723 (test-all-vars ns-obj))
724 (do-report {:type :end-test-ns, :ns ns-obj}))
725 @*report-counters*))
726
727
728
729 ;;; RUNNING TESTS: HIGH-LEVEL FUNCTIONS
730
731 (defn run-tests
732 "Runs all tests in the given namespaces; prints results.
733 Defaults to current namespace if none given. Returns a map
734 summarizing test results."
735 {:added "1.1"}
736 ([] (run-tests *ns*))
737 ([& namespaces]
738 (let [summary (assoc (apply merge-with + (map test-ns namespaces))
739 :type :summary)]
740 (do-report summary)
741 summary)))
742
743 (defn run-all-tests
744 "Runs all tests in all namespaces; prints results.
745 Optional argument is a regular expression; only namespaces with
746 names matching the regular expression (with re-matches) will be
747 tested."
748 {:added "1.1"}
749 ([] (apply run-tests (all-ns)))
750 ([re] (apply run-tests (filter #(re-matches re (name (ns-name %))) (all-ns)))))
751
752 (defn successful?
753 "Returns true if the given test summary indicates all tests
754 were successful, false otherwise."
755 {:added "1.1"}
756 [summary]
757 (and (zero? (:fail summary 0))
758 (zero? (:error summary 0))))