diff --git a/README.md b/README.md index 4c2a63c..8630a5b 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@ clojure.test.generative ======================================== -Test data generation and execution harness. Very early days. -This API will change. You have been warned. - +Generative test runner. Releases and Dependency Information ======================================== -Latest stable release: 0.1.4 +Latest stable release: 0.4.0 * [All Released Versions](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22test.generative%22) @@ -16,14 +14,14 @@ Latest stable release: 0.1.4 [Leiningen](https://github.com/technomancy/leiningen) dependency information: - [org.clojure/test.generative "0.1.4"] + [org.clojure/test.generative "0.4.0"] [Maven](http://maven.apache.org/) dependency information: org.clojure test.generative - 0.1.4 + 0.4.0 @@ -41,18 +39,6 @@ and a validator: To generate test data, see the fns in the generators namespace. Note that these functions shadow a bunch of clojure.core names. -You can run clojure.test and clojure.test.generative tests together -from the c.t.g. runner: - - (require '[clojure.test.generative.runner :as runner]) - (runner/-main "src/test/clojure" "src/examples/clojure") - -Assertion support is currently minimal. There is an `is` macro, -similar to clojure.test's, that provides rudimentaty contextual -reporting. You can also use plain assertions, or clojure.test -validation forms such as `is` and `are`, or any other forms that throw -exception on failure. No contextual reporting for these yet. - You can configure the runner with Java system properties: @@ -65,14 +51,8 @@ You can configure the runner with Java system properties: - - -
clojure.test.generative.msecDesired test run duration
clojure.test.generative.handlersComma-delimited list of handlers
-The default handler prints test run to stdout, but others could -e.g. put test events in a database. - Developer Information ======================================== @@ -84,20 +64,6 @@ Developer Information * [Compatibility Test Matrix](http://build.clojure.org/job/test.generative-test-matrix/) -Change Log -==================== - -* Release 0.1.5 (in development) - * Can now run tests under clojure.test - * Tests produce data events that can be consumed by arbitrary reporting tools - * Example reporting integration with logback. - * Added `is` macro with more detailed reporting than `clojure.test/is` - * Removed collection based input generators. Input generators must be fns. - * Removed duplicate input check. Tests can be called multiple times with same input. -* Release 0.1.4 on 2012.01.03 - * Initial version - - Copyright and License ======================================== diff --git a/pom.xml b/pom.xml index fea0e4b..4b5173a 100644 --- a/pom.xml +++ b/pom.xml @@ -59,19 +59,13 @@ org.clojure tools.namespace - 0.1.1 + 0.2.3 org.clojure data.generators 0.1.2 - - ch.qos.logback - logback-classic - 1.0.6 - provided - diff --git a/src/main/clojure/clojure/test/generative/runner.clj b/src/main/clojure/clojure/test/generative/runner.clj index dd94f6d..b4096d2 100644 --- a/src/main/clojure/clojure/test/generative/runner.clj +++ b/src/main/clojure/clojure/test/generative/runner.clj @@ -17,7 +17,7 @@ (def ^:private config-mapping [["clojure.test.generative.threads" - [:threads] + [:nthreads] read-string (max 1 (dec (.availableProcessors (Runtime/getRuntime))))] ["clojure.test.generative.msec" @@ -33,7 +33,6 @@ (if (seq val) (assoc-in m path (coerce val)) (assoc-in m path default)))) - {} config-mapping)) (def ^:private ^java.util.Random rnd (java.util.Random. (System/currentTimeMillis))) @@ -43,10 +42,10 @@ (locking rnd (.nextInt rnd))) -(defprotocol TestContainer +(defprotocol Testable (get-tests [_])) -(extend-protocol TestContainer +(extend-protocol Testable clojure.lang.Var (get-tests [v] @@ -65,23 +64,22 @@ [m] m)) -(defn find-vars-in-namespaces +(defn- find-vars-in-namespaces [& nses] (when nses (reduce (fn [v ns] (into v (vals (ns-interns ns)))) [] nses))) -(defn find-vars-in-dirs +(defn- find-vars-in-dirs [& dirs] (let [nses (mapcat #(ns/find-namespaces-in-dir (java.io.File. ^String %)) dirs)] (doseq [ns nses] (require ns)) (apply find-vars-in-namespaces nses))) -(defn run-one +(defn- run-one "Run f (presumably for side effects) repeatedly on n threads, until msec has passed or somebody throws an exception. Returns as many status maps as seeds passed in." - [{:keys [test input-gen]} msec seeds] - (prn) (prn test) + [{:keys [test input-gen]} {:keys [msec seeds]}] (let [f (eval test) start (System/currentTimeMillis) futs (mapv @@ -106,24 +104,24 @@ seeds)] (map deref futs))) -(defn run-n - "Run tests in parallel on nthreads, dividing msec equally between the tests." - [nthreads msec tests] - (mapcat #(run-one % (/ msec (count tests)) (repeatedly nthreads next-seed)) tests)) - -(defn failed? +(defn- failed? "Does test result indicate a failure?" [result] (contains? result :exception)) -(defn run-vars - "Designed for interactive use. Prints results to *out* and throws - on first failure encountered." - [nthreads msec & test-containers] - (doseq [result (run-n nthreads msec (mapcat get-tests test-containers))] - (if (failed? result) - (throw (ex-info "Generative test failed" result)) - (prn result)))) +(defn- run-n + "Run tests in parallel on nthreads, dividing msec equally between the tests. + Returns a list of maps of :iter, :seed, :test." + [{:keys [nthreads msec]} tests] + (mapcat #(run-one % + {:msec (/ msec (count tests)) + :seeds (repeatedly nthreads next-seed)}) + tests)) + +(defn- prf + "Print and flush." + [s] + (print s) (flush)) (defn dir-tests "Returns all tests in dirs" @@ -134,22 +132,41 @@ (apply find-vars-in-namespaces) (mapcat get-tests)))) +(defn inputs + "For interactive use. Returns an infinite sequence of inputs for + a test." + [test] + ((:input-gen test))) + +(defn run + "Designed for interactive use. Prints results to *out* and throws + on first failure encountered." + [nthreads msec & test-containers] + (doseq [result (run-n {:nthreads nthreads + :msec msec} + (mapcat get-tests test-containers))] + (if (failed? result) + (throw (ex-info "Generative test failed" result)) + (prn result)))) + (defn run-suite "Designed for test suite use." - [{:keys [threads msec verbose]} tests] - (reduce - (fn [{:keys [failures iters tests]} result] - (if (or verbose (:exception result)) - (do (prn) (prn result)) - (print ".")) - (when (:exception result) - (.printStackTrace ^Throwable (:exception result))) - (flush) - {:failures (+ failures (if (:exception result) 1 0)) - :iters (+ iters (:iter result)) - :tests (inc tests)}) - {:failures 0 :iters 0 :tests 0} - (run-n threads msec tests))) + [{:keys [nthreads msec progress]} tests] + (let [progress (or progress #(prf "."))] + (reduce + (fn [{:keys [failures iters tests]} result] + (when (:exception result) + (.printStackTrace ^Throwable (:exception result))) + (if (:exception result) + (prn result) + (progress)) + {:failures (+ failures (if (:exception result) 1 0)) + :iters (+ iters (:iter result)) + :tests (+ tests (/ 1 nthreads))}) + {:failures 0 :iters 0 :tests 0} + (run-n {:nthreads nthreads + :msec msec} + tests)))) (defn -main "Command line entry point. Calls System.exit!"