如果在 clojure.test deftest 期间发生异常,则错误会传递给带有 :error 键的 clojure.test/report,这默认会打印整个调用栈。该调用栈包括测试框架本身,如果没有通过外部测试运行器(如 lein test、clojure.main 等)调用,则会产生 ~60 个调用栈深度,这些都是无关紧要的噪声。
存在全局变量 clojure.test/stack-trace-depth,默认为 nil(所有)。此 global 可以在调用 clojure.test 运行器周围绑定,以在测试期间出现异常时看到更少的调用栈,但这对外部测试运行器来说既困难又容易出错。
从调用栈底部过滤框架噪声并只显示相关帧将非常有用。
给定一个测试,如
(ns foo.core-test
(:require [clojure.test :refer :all]))
(deftest a-test
(testing "FIXME, I fail."
(throw (ex-info "I suck" {:a 1}))
(is (= 0 1))))
报告的错误(此处来自 lein test,但任何外部运行器都类似),只有前两行是相关的,其余的都是无关紧要的噪声
ERROR in (a-test) (core_test.clj:13)
Uncaught exception, not in assertion.
expected: nil
actual: clojure.lang.ExceptionInfo: I suck
{:a 1}
at foo.core_test$fn__364.invokeStatic (core_test.clj:13)
foo.core_test/fn (core_test.clj:11)
clojure.test$test_var$fn__9737.invoke (test.clj:717) ;; noise from here down
clojure.test$test_var.invokeStatic (test.clj:717)
clojure.test$test_var.invoke (test.clj:708)
clojure.test$test_vars$fn__9763$fn__9768.invoke (test.clj:735)
clojure.test$default_fixture.invokeStatic (test.clj:687)
clojure.test$default_fixture.invoke (test.clj:683)
clojure.test$test_vars$fn__9763.invoke (test.clj:735)
clojure.test$default_fixture.invokeStatic (test.clj:687)
clojure.test$default_fixture.invoke (test.clj:683)
clojure.test$test_vars.invokeStatic (test.clj:731)
clojure.test$test_all_vars.invokeStatic (test.clj:737)
clojure.test$test_ns.invokeStatic (test.clj:758)
clojure.test$test_ns.invoke (test.clj:743)
user$eval224$fn__287.invoke (form-init4292042596091073068.clj:1)
clojure.lang.AFn.applyToHelper (AFn.java:156)
clojure.lang.AFn.applyTo (AFn.java:144)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.core$apply.invoke (core.clj:660)
leiningen.core.injected$compose_hooks$fn__154.doInvoke (form-init4292042596091073068.clj:1)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:665)
clojure.core$apply.invoke (core.clj:660)
leiningen.core.injected$run_hooks.invokeStatic (form-init4292042596091073068.clj:1)
leiningen.core.injected$run_hooks.invoke (form-init4292042596091073068.clj:1)
leiningen.core.injected$prepare_for_hooks$fn__159$fn__160.doInvoke (form-init4292042596091073068.clj:1)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.lang.AFunction$1.doInvoke (AFunction.java:31)
clojure.lang.RestFn.invoke (RestFn.java:408)
clojure.core$map$fn__5866.invoke (core.clj:2755)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:51)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1792)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.test$run_tests.invokeStatic (test.clj:768)
clojure.test$run_tests.doInvoke (test.clj:768)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:665)
clojure.core$apply.invoke (core.clj:660)
user$eval224$fn__299$fn__332.invoke (form-init4292042596091073068.clj:1)
user$eval224$fn__299$fn__300.invoke (form-init4292042596091073068.clj:1)
user$eval224$fn__299.invoke (form-init4292042596091073068.clj:1)
user$eval224.invokeStatic (form-init4292042596091073068.clj:1)
user$eval224.invoke (form-init4292042596091073068.clj:1)
clojure.lang.Compiler.eval (Compiler.java:7177)
clojure.lang.Compiler.eval (Compiler.java:7167)
clojure.lang.Compiler.load (Compiler.java:7636)
clojure.lang.Compiler.loadFile (Compiler.java:7574)
clojure.main$load_script.invokeStatic (main.clj:475)
clojure.main$init_opt.invokeStatic (main.clj:477)
clojure.main$init_opt.invoke (main.clj:477)
clojure.main$initialize.invokeStatic (main.clj:508)
clojure.main$null_opt.invokeStatic (main.clj:542)
clojure.main$null_opt.invoke (main.clj:539)
clojure.main$main.invokeStatic (main.clj:664)
clojure.main$main.doInvoke (main.clj:616)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.lang.Var.applyTo (Var.java:705)
clojure.main.main (main.java:40)
我们在其他地方执行了过滤框架的操作,我认为将过滤操作进行调整以提高默认体验并不困难(如果需要,仍然可以是一个全局变量来决定是否过滤)。