Permalink
Browse files

Merge tag '0.4.0'

0.4.0
  • Loading branch information...
2 parents c69604a + 9cc05c6 commit a48264ba2de59676c67d55df09a203f4d028a9ce @pjstadig committed Mar 22, 2013
Showing with 142 additions and 31 deletions.
  1. +2 −0 CHANGELOG.org
  2. +25 −0 doc/Fixtures.org
  3. +1 −1 project.clj
  4. +72 −30 src/conjecture/core.clj
  5. +18 −0 test/conjecture/singleton_fixtures.clj
  6. +24 −0 test/conjecture/test/singleton_fixtures.clj
View
@@ -1,5 +1,7 @@
#+STARTUP: hidestars showall
* conjecture changelog
+** 0.4.0
+ - Adds singleton fixtures.
** 0.3.0
- Compatible with Clojure 1.2.1.
- Renamed groupId to conjecture.
View
@@ -80,6 +80,31 @@
When ~test-frobnicate~ runs, it will run ~a-useful-fixture~ only once, even
though it appears in the fixture chain more than once.
+** Singleton fixtures
+ At times one may want to have a fixture run around the entire test run, for
+ example, to run some external service for the duration of the test run
+ instead of having a once fixture that starts and stops the service for each
+ namespace. This is called 'singleton' fixture.
+
+ To register a singleton fixture, you need to create a
+ ~conjecture/singleton_fixtures.clj~ file in your project's test
+ classpath. This file should define the ~conjecture.singleton-fixtures~
+ namespace and register singleton fixtures like this:
+
+ : (ns conjecture.singleton-fixtures
+ : (:use conjecture.core))
+ :
+ : (defn run-the-service [f]
+ : (start-the-service)
+ : (try
+ : (f)
+ : (finally
+ : (stop-the-service))))
+ :
+ : (use-singleton-fixtures run-the-service)
+
+ Now anytime that ~conjecture.core/run-tests~ is called, the ~run-the-service~
+ fixture will be run around the entire test run.
** Fixture best practices
- *Anonymous fixtures* If you define anonymous fixtures it is recommended
that you give the anonymous function a name. For example:
View
@@ -1,4 +1,4 @@
-(defproject conjecture "0.3.0"
+(defproject conjecture "0.4.0"
:description "A clojure.test compatible third-party testing library for
Clojure."
:url "http://github.com/pjstadig/conjecture"
@@ -236,7 +236,8 @@
"}
conjecture.core
(:require [clojure.template :as temp]
- [clojure.stacktrace :as stack]))
+ [clojure.stacktrace :as stack])
+ (:import (java.io FileNotFoundException)))
;; Nothing is marked "private" here, so you can rebind things to plug
;; in your own testing or reporting frameworks.
@@ -349,7 +350,7 @@
"Add file and line information to a test result and call report.
If you are writing a custom assert-expr method, call this function
to pass test results to report."
- {:added "1.2"}
+ {:added "0.1.0"}
[m]
(report
(case
@@ -676,6 +677,24 @@
(defmethod use-fixtures :once [fixture-type & args]
(add-ns-meta ::once-fixtures args))
+(defonce singleton-fixtures (atom []))
+(def ^:dynamic *singletons-run?* false)
+
+(defn load-singletons! []
+ (try
+ (require 'conjecture.singleton-fixtures)
+ (catch FileNotFoundException _)))
+
+(defn use-singleton-fixtures
+ "Wrap the entire test run in a fixture function to perform setup and
+ teardown."
+ {:added "0.4.0"}
+ [& args]
+ (when-not (= (ns-name *ns*) 'conjecture.singleton-fixtures)
+ (throw (Exception. (str "Singletons fixtures may only be defined in the "
+ "conjecture.singleton-fixtures namespace"))))
+ (reset! singleton-fixtures args))
+
(defn- default-fixture
"The default, empty, fixture function. Just calls its argument."
{:added "0.1.0"}
@@ -705,6 +724,9 @@
;;; RUNNING TESTS: LOW-LEVEL FUNCTIONS
+(defn singleton-fixture-fn []
+ (join-fixtures @singleton-fixtures))
+
(defn once-fixture-fn [ns]
(join-fixtures (::once-fixtures (meta ns))))
@@ -715,42 +737,61 @@
(def ^{:dynamic true} *each-fixtures* #{})
+(defmacro with-singleton-fixtures [& body]
+ `(let [f# (fn [] ~@body)]
+ (load-singletons!)
+ (if *singletons-run?*
+ (f#)
+ (let [fixtures# (singleton-fixture-fn)]
+ (binding [*singletons-run?* true]
+ (fixtures# f#))))))
+
+(defmacro with-once-fixtures [ns & body]
+ `(let [f# (fn [] ~@body)]
+ (if (contains? *once-fixtures* ~ns)
+ (f#)
+ (let [fixtures# (once-fixture-fn ~ns)]
+ (binding [*once-fixtures* (conj *once-fixtures* ~ns)]
+ (fixtures# f#))))))
+
+(defmacro with-each-fixtures [ns & body]
+ `(let [f# (fn [] ~@body)]
+ (if (contains? *each-fixtures* ~ns)
+ (f#)
+ (let [fixtures# (each-fixture-fn ~ns)]
+ (binding [*each-fixtures* (conj *each-fixtures* ~ns)]
+ (fixtures# f#))))))
+
(defn test-var
"If v has a function in its :test metadata, calls that function,
with *testing-vars* bound to (conj *testing-vars* v)."
{:dynamic true, :added "0.1.0"}
[v]
(let [ns (:ns (meta v))]
(when-let [t (:test (meta v))]
- (if (contains? *once-fixtures* ns)
- (if (contains? *each-fixtures* ns)
- (binding [*testing-vars* (conj *testing-vars* v)]
- (do-report {:type :begin-test-var, :var v})
- (inc-report-counter :test)
- (try (t)
- (catch Throwable e
- (do-report {:type :error,
- :message "Uncaught exception, not in assertion."
- :expected nil, :actual e})))
- (do-report {:type :end-test-var, :var v}))
- (let [fixtures (each-fixture-fn ns)]
- (binding [*each-fixtures* (conj *each-fixtures* ns)]
- (fixtures (fn [] (test-var v))))))
- (let [fixtures (once-fixture-fn ns)]
- (binding [*once-fixtures* (conj *once-fixtures* ns)]
- (fixtures (fn [] (test-var v)))))))))
+ (with-singleton-fixtures
+ (with-once-fixtures ns
+ (with-each-fixtures ns
+ (binding [*testing-vars* (conj *testing-vars* v)]
+ (do-report {:type :begin-test-var, :var v})
+ (inc-report-counter :test)
+ (try
+ (t)
+ (catch Throwable e
+ (do-report {:type :error,
+ :message "Uncaught exception, not in assertion."
+ :expected nil, :actual e})))
+ (do-report {:type :end-test-var, :var v}))))))))
(defn test-all-vars
"Calls test-var on every var interned in the namespace, with fixtures."
{:added "0.1.0"}
[ns]
- (if (contains? *once-fixtures* ns)
- (doseq [v (vals (ns-interns ns))]
- (when (:test (meta v))
- (test-var v)))
- (let [fixtures (once-fixture-fn ns)]
- (binding [*once-fixtures* (conj *once-fixtures* ns)]
- (fixtures (fn [] (test-all-vars ns)))))))
+ (with-singleton-fixtures
+ (with-once-fixtures ns
+ (doseq [v (vals (ns-interns ns))]
+ (when (:test (meta v))
+ (test-var v))))))
(defn test-ns
"If the namespace defines a function named test-ns-hook, calls that.
@@ -784,10 +825,11 @@
{:added "0.1.0"}
([] (run-tests *ns*))
([& namespaces]
- (let [summary (assoc (apply merge-with + (map test-ns namespaces))
- :type :summary)]
- (do-report summary)
- summary)))
+ (with-singleton-fixtures
+ (let [summary (assoc (apply merge-with + (map test-ns namespaces))
+ :type :summary)]
+ (do-report summary)
+ summary))))
(defn run-all-tests
"Runs all tests in all namespaces; prints results.
@@ -0,0 +1,18 @@
+;;;; Copyright © Paul Stadig. 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 conjecture.singleton-fixtures
+ (:use conjecture.core))
+
+(def called (atom 0))
+
+(use-singleton-fixtures (fn [f]
+ (swap! called inc)
+ (f)))
@@ -0,0 +1,24 @@
+;;;; Copyright © Paul Stadig. 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 conjecture.test.singleton-fixtures
+ (:require [conjecture.test.core]
+ [conjecture.test.fixtures])
+ (:use [conjecture.core])
+ (:import (java.io PrintWriter StringWriter)))
+
+(deftest test-singleton-fixtures
+ (is (= 1 @conjecture.singleton-fixtures/called)))
+
+(defn test-ns-hook []
+ (binding [*test-out* (PrintWriter. (StringWriter.))]
+ (run-tests 'conjecture.test.core)
+ (run-tests 'conjecture.test.fixtures))
+ (test-all-vars 'conjecture.test.singleton-fixtures))

0 comments on commit a48264b

Please sign in to comment.