如何在测试套件中包含clojure.spec'd函数

Nut*_*tim 10 unit-testing clojure generative-testing

无论如何在广义测试套件中包含clojure.spec'd函数?我知道我们可以注册规格和直接规范功能.

(ns foo
  (:require [clojure.spec :as s]
            [clojure.spec.test :as stest]))

(defn average [list-sum list-count]
  (/ list-sum list-count))

(s/fdef average
        :args (s/and (s/cat :list-sum float? :list-count integer?)
                     #(not (zero? (:list-count %))))
        :ret number?)
Run Code Online (Sandbox Code Playgroud)

后来,如果我想针对该spec'd函数运行生成测试,我可以使用stest/check.

=> (stest/check `average)
({:spec #object[clojure.spec$fspec_impl$reify__14282 0x68e9f37c "clojure.spec$fspec_impl$reify__14282@68e9f37c"], :clojure.spec.test.check/ret {:result true, :num-tests 1000, :seed 1479587517232}, :sym edgar.core.analysis.lagging/average})
Run Code Online (Sandbox Code Playgroud)

但是i)无论如何都要在我的通用测试套件中包含这些测试运行?我正在考虑test.check所具有的那种clojure.test集成.我能看到的最接近的东西ii)是(见这里)函数.但这似乎只是让我们开始检查repl.不是我想要的.另外,iii)是否注册了功能规格?stest/instrument

(defspec foo-test 
         100 

         ;; NOT this
         #_(prop/for-all [v ...]
           (= v ...))

         ;; but THIS
         (stest/some-unknown-spec-fn foo))
Run Code Online (Sandbox Code Playgroud)

Nut*_*tim 9

好的,解决了这个.事实证明,没有开箱即用的解决方案.但是一些关于clojure-spec slack channel的人已经defspec-testclojure.spec.testclojure.test提供了一个解决方案.

所以考虑到问题中的代码.您可以A)定义defspec-test获取测试名称的宏和规范函数列表.然后,您可以B)在您的测试套件中使用它.

谢谢Clojure社区!! 希望这样的实用功能使其成为核心库.

一个)

(ns foo.test
  (:require [clojure.test :as t]
            [clojure.string :as str]))

(defmacro defspec-test
  ([name sym-or-syms] `(defspec-test ~name ~sym-or-syms nil))
  ([name sym-or-syms opts]
   (when t/*load-tests*
     `(def ~(vary-meta name assoc
                       :test `(fn []
                                (let [check-results# (clojure.spec.test/check ~sym-or-syms ~opts)
                                      checks-passed?# (every? nil? (map :failure check-results#))]
                                  (if checks-passed?#
                                    (t/do-report {:type    :pass
                                                  :message (str "Generative tests pass for "
                                                                (str/join ", " (map :sym check-results#)))})
                                    (doseq [failed-check# (filter :failure check-results#)
                                            :let [r# (clojure.spec.test/abbrev-result failed-check#)
                                                  failure# (:failure r#)]]
                                      (t/do-report
                                        {:type     :fail
                                         :message  (with-out-str (clojure.spec/explain-out failure#))
                                         :expected (->> r# :spec rest (apply hash-map) :ret)
                                         :actual   (if (instance? Throwable failure#)
                                                     failure#
                                                     (:clojure.spec.test/val failure#))})))
                                  checks-passed?#)))
        (fn [] (t/test-var (var ~name)))))))
Run Code Online (Sandbox Code Playgroud)

B)

(ns foo-test
  (:require [foo.test :refer [defspec-test]]
            [foo]))


(defspec-test test-average [foo/average])
Run Code Online (Sandbox Code Playgroud)