为了测试和数据生成,我一直在玩Clojure Spec,我看到了一些奇怪的行为,在REPL中,函数在单元测试和验证中工作,但是带有spec.test/check的生成测试失败了。
我创建了一组这样的规范:
(s/def ::significant-string (s/with-gen
(s/and string? #(not (nil? %)))
(fn [] (gen/such-that #(not= % "")
(gen/string-alphanumeric)))))
(s/def ::byte-stream
(s/with-gen #(instance? java.io.ByteArrayInputStream %)
(gen/fmap #(string->stream %) (gen/string-alphanumeric))))
(s/fdef string->stream
:args (s/cat :s ::significant-string)
:ret ::byte-stream
:fn #(instance? java.io.ByteArrayInputStream %))
和新生力量的执行情况:
(defn string->stream
"Given a string, return a java.io.ByteArrayInputStream"
([s] {:pre [(s/valid? ::significant-string s)]
:post [(s/valid? ::byte-stream %)]}
(string->stream s "UTF-8"))
([s encoding]
(-> s
(.getBytes encoding)
(java.io.ByteArrayInputStream.))))
在REPL中,我看到了我希望从规范的生成和测试中看到的:
=> (instance? java.io.ByteArrayInputStream (string->stream "test"))
true
=> (s/valid? ::byte-stream (string->stream "0"))
true
=> (s/exercise-fn 'calais-response-processor.rdf-core/string->stream)
([("Y") #object[java.io.ByteArrayInputStream 0x57210dd7 "java.io.ByteArrayInputStream@57210dd7"]] [("d") #object[java.io.ByteArrayInputStream 0x7ec14113 "java.io.ByteArrayInputStream@7ec14113"]] [("5") #object[java.io.ByteArrayInputStream 0x1e85195b "java.io.ByteArrayInputStream@1e85195b"]] [("9c") #object[java.io.ByteArrayInputStream 0x3769ddef "java.io.ByteArrayInputStream@3769ddef"]] [("P0N") #object[java.io.ByteArrayInputStream 0x68793160 "java.io.ByteArrayInputStream@68793160"]] [("7tvN1") #object[java.io.ByteArrayInputStream 0x1cc43ca5 "java.io.ByteArrayInputStream@1cc43ca5"]] [("LjH4U") #object[java.io.ByteArrayInputStream 0x2a3da1a7 "java.io.ByteArrayInputStream@2a3da1a7"]] [("W") #object[java.io.ByteArrayInputStream 0x534287aa "java.io.ByteArrayInputStream@534287aa"]] [("x867VLr") #object[java.io.ByteArrayInputStream 0x72915e93 "java.io.ByteArrayInputStream@72915e93"]] [("moucN3vr") #object[java.io.ByteArrayInputStream 0x4f0d7570 "java.io.ByteArrayInputStream@4f0d7570"]])
但我不明白为什么我在测试/检查中看到这个:
(stest/check 'calais-response-processor.rdf-core/string->stream)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__2451 0x1acb0d46 "clojure.spec.alpha$fspec_impl$reify__2451@1acb0d46"], :clojure.spec.test.check/ret {:shrunk {:total-nodes-visited 4, :depth 3, :pass? false, :result #error {
:cause "Specification-based check failed"
:data {:clojure.spec.alpha/problems [{:path [:fn], :pred (clojure.core/fn [%] (clojure.core/instance? java.io.ByteArrayInputStream %)), :val {:args {:s "0"}, :ret #object[java.io.ByteArrayInputStream 0x7bee9d86 "java.io.ByteArrayInputStream@7bee9d86"]}, :via [], :in []}], :clojure.spec.alpha/spec #object[clojure.spec.alpha$spec_impl$reify__1987 0x16a19b4c "clojure.spec.alpha$spec_impl$reify__1987@16a19b4c"], :clojure.spec.alpha/value {:args {:s "0"}, :ret #object[java.io.ByteArrayInputStream 0x7bee9d86 "java.io.ByteArrayInputStream@7bee9d86"]}, :clojure.spec.test.alpha/args ("0"), :clojure.spec.test.alpha/val {:args {:s "0"}, :ret #object[java.io.ByteArrayInputStream 0x7bee9d86 "java.io.ByteArrayInputStream@7bee9d86"]}, :clojure.spec.alpha/failure :check-failed}
:via
[{:type clojure.lang.ExceptionInfo
:message "Specification-based check failed"
:data {:clojure.spec.alpha/problems [{:path [:fn], :pred (clojure.core/fn [%] (clojure.core/instance? java.io.ByteArrayInputStream %)), :val {:args {:s "0"}, :ret #object[java.io.ByteArrayInputStream 0x7bee9d86 "java.io.ByteArrayInputStream@7bee9d86"]}, :via [], :in []}], :clojure.spec.alpha/spec #object[clojure.spec.alpha$spec_impl$reify__1987 0x16a19b4c "clojure.spec.alpha$spec_impl$reify__1987@16a19b4c"], :clojure.spec.alpha/value {:args {:s "0"}, :ret #object[java.io.ByteArrayInputStream 0x7bee9d86 "java.io.ByteArrayInputStream@7bee9d86"]}, :clojure.spec.test.alpha/args ("0"), :clojure.spec.test.alpha/val {:args {:s "0"}, :ret #object[java.io.ByteArrayInputStream 0x7bee9d86 "java.io.ByteArrayInputStream@7bee9d86"]}, :clojure.spec.alpha/failure :check-failed}
:at [clojure.core$ex_info invokeStatic "core.clj" 4739]}]
:trace
[[clojure.core$ex_info invokeStatic "core.clj" 4739]
[clojure.core$ex_info invoke "core.clj" 4739]
...
...(lots more)
虽然返回的对象在我看来是"ok“,但它似乎与生成器fn组合有关。
发布于 2019-01-25 15:59:14
:fn #(instance? java.io.ByteArrayInputStream %))
问题在于,当函数返回值实际上是用包含输入和返回值的映射调用时,:fn
规范似乎只期望函数返回值。试一试这个版本:
:fn (fn [{:keys [args ret]}]
(instance? java.io.ByteArrayInputStream ret))
:fn
规范应该是一个函数,它接受一个包含函数的输入:args
和输出:ret
值的映射。它的目的是比较函数的输出相对于其输入。
在本例中,:fn
规范似乎是在做出与:ret
规范相同的断言,并且它不查看:args
,因此如果输入/输出之间没有有意义的断言,您可能不想在这里使用:fn
规范--这只会断言返回值,冗余。
在REPL中,我看到了我希望从规范的生成和测试中看到的东西。
您之所以只看到check
的失败,是因为其他调用都没有考虑到您的函数的:fn
规范,例如s/exercise-fn
没有考虑:fn
规范。
我用:fn
规范这里做了一些例子。
https://stackoverflow.com/questions/54360863
复制相似问题