diff --git a/README.md b/README.md index c832bbe..108493f 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ The `checking` macro is intended to be used with '[com.gfredericks.test.chuck.clojure-test :refer [checking]]) (deftest my-test - (checking "that positive numbers are positive" 100 + (checking "that positive numbers are positive" [x gen/s-pos-int] (is (pos? x)) (is (> x 0)))) diff --git a/src/com/gfredericks/test/chuck/clojure_test.cljc b/src/com/gfredericks/test/chuck/clojure_test.cljc index 7117de2..1522130 100644 --- a/src/com/gfredericks/test/chuck/clojure_test.cljc +++ b/src/com/gfredericks/test/chuck/clojure_test.cljc @@ -106,27 +106,43 @@ (ct/report reports)) (defmacro checking - "A macro intended to replace the testing macro in clojure.test with a + {:doc "A macro intended to replace the testing macro in clojure.test with a generative form. To make (testing \"doubling\" (is (= (* 2 2) (+ 2 2)))) generative, you simply have to change it to - (checking \"doubling\" 100 [x gen/int] (is (= (* 2 x) (+ x x)))). + (checking \"doubling\" [x gen/int] (is (= (* 2 x) (+ x x)))). - You can optionally pass in a map options instead of the number of tests, + You can optionally pass the same options as test.check's defspec, which will be passed to `clojure.test.check/quick-check`, e.g.: - (checking \"doubling\" {:num-tests 100 :seed 123 :max-size 10} + (checking \"doubling\" 100 ;; number + [x gen/int] + (is (= (* 2 x) (+ x x)))) + + (checking \"doubling\" {:num-tests 100 :seed 123 :max-size 10} ;; options map [x gen/int] (is (= (* 2 x) (+ x x)))) For background, see http://blog.colinwilliams.name/blog/2015/01/26/alternative-clojure-dot-test-integration-with-test-dot-check/" - [name num-tests-or-options bindings & body] - `(-testing ~name - (fn [] - (let [final-reports# (atom [])] - (qc-and-report-exception final-reports# ~num-tests-or-options ~bindings ~@body) - (doseq [r# @final-reports#] - (-report r#)))))) + :arglists '([name bindings & body] [name num-tests-or-options bindings & body])} + [name & check-decl] + (let [[num-tests-or-options bindings body] + (cond + (vector? (second check-decl)) + [(first check-decl) (second check-decl) (nnext check-decl)] + + (vector? (first check-decl)) + [nil (first check-decl) (next check-decl)] + + :else (throw (#?(:clj IllegalArgumentException. + :cljs js/Error.) "Arguments to `checking` must be either [name bindings & body] or [name num-tests-or-options bindings & body]")))] + `(-testing ~name + (fn [] + (let [final-reports# (atom []) + num-tests-or-options# (tc.clojure-test/process-options ~num-tests-or-options)] + (qc-and-report-exception final-reports# num-tests-or-options# ~bindings ~@body) + (doseq [r# @final-reports#] + (-report r#))))))) (defmacro for-all "An alternative to clojure.test.check.properties/for-all that uses diff --git a/test/com/gfredericks/test/chuck/clojure_test_test.cljc b/test/com/gfredericks/test/chuck/clojure_test_test.cljc index 1733c10..053a03d 100644 --- a/test/com/gfredericks/test/chuck/clojure_test_test.cljc +++ b/test/com/gfredericks/test/chuck/clojure_test_test.cljc @@ -1,6 +1,6 @@ (ns com.gfredericks.test.chuck.clojure-test-test (:require #?(:clj [clojure.test :refer :all]) - #?(:cljs [cljs.test :refer-macros [deftest is]]) + #?(:cljs [cljs.test :refer-macros [deftest is testing]]) [clojure.test.check :refer [quick-check]] [clojure.test.check.generators :as gen] [com.gfredericks.test.chuck.clojure-test #?(:clj :refer :cljs :refer-macros) [checking for-all]])) @@ -12,6 +12,13 @@ (is (< i 0)))) (deftest options-test + ;; no option is OK, defaults to 100 tests + (let [nb-runs (atom 0)] + (checking "no option works" [i gen/s-pos-int] + (swap! nb-runs inc) + (is (pos? i))) + (testing "no option means 100 runs (test.check's default)" + (is (= 100 @nb-runs)))) ;; empty map is OK, defaults to 100 tests (checking "strings are strings" {} [s gen/string-ascii] (is (string? s))) @@ -23,7 +30,16 @@ (is (contains? #{-1 0 1} i))) ;; passes because of max-size (checking "short strings" {:num-tests 100 :max-size 9} [s gen/string-ascii] - (is (< (count s) 10)))) + (is (< (count s) 10))) + ;; using non-literal expression as option + (let [opts {:max-size 9}] + (checking "short strings again" (assoc opts :num-tests 100) [s gen/string-ascii] + (is (< (count s) 10)))) + ;; bad options throws + (testing "bad option throws" + (is (thrown? #?(:clj Exception :cljs js/Object) + (eval `(checking "numbers are numbers" "opts as string" [i# gen/int] + (is (integer? i#)))))))) (deftest counter (checking "increasing" 100 [i gen/s-pos-int]