简体   繁体   中英

clojure.test throws? not working in the repl

Following the docstring in the source of clojure.test , I issue the following in the repl:

(use 'clojure.test)
(is (thrown? ArithmeticException (/ 1 0)))

And other variations like substituting ArithmeticException with java.lang.ArithmeticException . Yet the exception is never captured by clojure.test but rather bubbles up all the way to the top:

> #error {  :cause "Divide by zero"  :via  [{:type java.lang.ArithmeticException    :message "Divide by zero"    :at
> [clojure.lang.Numbers divide "Numbers.java" 158]}]  :trace 
> [[clojure.lang.Numbers divide "Numbers.java" 158]  
> [clojure.lang.Numbers divide "Numbers.java" 3808]   [api.core$eval1305
> invokeStatic "form-init8750388124499546857.clj" 1]  
> [api.core$eval1305 invoke "form-init8750388124499546857.clj" 1]  
> [clojure.lang.Compiler eval "Compiler.java" 6927]  
> [clojure.lang.Compiler eval "Compiler.java" 6890]   [clojure.core$eval
> invokeStatic "core.clj" 3105]   [clojure.core$eval invoke "core.clj"
> 3101]   [clojure.main$repl$read_eval_print__7408$fn__7411 invoke
> "main.clj" 240]   [clojure.main$repl$read_eval_print__7408 invoke
> "main.clj" 240]   [clojure.main$repl$fn__7417 invoke "main.clj" 258]  
> [clojure.main$repl invokeStatic "main.clj" 258]   [clojure.main$repl
> doInvoke "main.clj" 174]   [clojure.lang.RestFn invoke "RestFn.java"
> 1523]  
> [clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__667
> invoke "interruptible_eval.clj" 87]   [clojure.lang.AFn applyToHelper
> "AFn.java" 152]   [clojure.lang.AFn applyTo "AFn.java" 144]  
> [clojure.core$apply invokeStatic "core.clj" 646]  
> [clojure.core$with_bindings_STAR_ invokeStatic "core.clj" 1881]  
> [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1881]  
> [clojure.lang.RestFn invoke "RestFn.java" 425]  
> [clojure.tools.nrepl.middleware.interruptible_eval$evaluate
> invokeStatic "interruptible_eval.clj" 85]  
> [clojure.tools.nrepl.middleware.interruptible_eval$evaluate invoke
> "interruptible_eval.clj" 55]  
> [clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__712$fn__715
> invoke "interruptible_eval.clj" 222]  
> [clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__707
> invoke "interruptible_eval.clj" 190]   [clojure.lang.AFn run
> "AFn.java" 22]   [java.util.concurrent.ThreadPoolExecutor runWorker
> "ThreadPoolExecutor.java" 1142]  
> [java.util.concurrent.ThreadPoolExecutor$Worker run
> "ThreadPoolExecutor.java" 617]   [java.lang.Thread run "Thread.java"
> 745]]}

What might it be? Other stuff from clojure.test does work in the repl as expected.

Version information:

Leiningen 2.7.1 on Java 1.8.0_101 Java HotSpot(TM) 64-Bit Server VM

> nREPL server started on port 44025 on host 127.0.0.1 -
> nrepl://127.0.0.1:44025 REPL-y 0.3.7, nREPL 0.2.12 Clojure 1.8.0 Java
> HotSpot(TM) 64-Bit Server VM 1.8.0_101-b13

use it/wrap it in (clojure.test/ deftest ...)


assuming:

(require '[clojure.test :as t])

pass example

(t/deftest a 
  (t/testing "a test" 
    (t/is (thrown? ArithmeticException (/ 1 0)))))

(a)
nil

fail example

(t/deftest a 
  (t/testing "a test" 
    (t/is (thrown? NullPointerException (/ 1 0)))))

(a)
; ERROR in (a) (Numbers.java:158)
; a test
; expected: (thrown? NullPointerException (/ 1 0))
; actual: java.lang.ArithmeticException: Divide by zero

you can also use t/run-tests to get a summary/stats


alternatively it seems you can use t/test-var directly like so

(t/test-var (t/is (thrown? ArithmeticException (/ 1 0))))
nil

You may also be interested in the throws? macro from the Tupelo library . It is more versatile and easier to use than the thrown? clause from clojure.test . Note that thrown? in clojure.test is not a normal Clojure function or macro, but is a custom expression recognized only within the is macro).

The tupelo.test/throws? macro is a normal Clojure macro that can be used anywhere.

throws? is meant to be used alone, and should not be wrapped within an is statement. Note that throws? always returns either true or false , which can be used in further processing.

> lein repl
user=> (use 'tupelo.test)
user=> (throws?  (/ 1 0))
true    ; <= return value

user=> (throws? Exception (/ 1 0))
true    ; <= return value

user=> (throws? ArithmeticException (/ 1 0))
true    ; <= return value

If the expression does not thrown an exception, or thows a different type of exception, then throws? will register a failed test via (clojure.test/is false) , and will also return false :

user=> (throws? NullPointerException (/ 1 0))
FAIL in () (form-init2868942318552383212.clj:1)
expected: (try (/ 1 0) false (catch NullPointerException t1__13775__auto__ true) (catch java.lang.Throwable t2__13776__auto__ false))
  actual: false
false   ; <= return value

clj.core=> (throws? ArithmeticException (+ 1 0))
FAIL in () (form-init4299343763551622058.clj:1)
expected: (try (+ 1 0) false (catch ArithmeticException t1__13761__auto__ true) (catch java.lang.Throwable t2__13762__auto__ false))
  actual: false
false    ; <= return value

clj.core=> (throws? (+ 1 0))
FAIL in () (form-init4299343763551622058.clj:1)
expected: (try (+ 1 0) false (catch java.lang.Throwable t3__13763__auto__ true))
  actual: false
false    ; <= return value

A typical usage of throws? is illustrated by tupelo.core's own unit tests:

(ns test.tupelo.core
  (:use clojure.test tupelo.test )
  (:require [tupelo.core :as t] ))
(t/refer-tupelo)

(deftest t-grab
  (let [map1  {:a 1 :b 2}]
    (is= 1    (grab :a map1))
    (is= 2    (grab :b map1))
    (throws?  (grab :c map1)) ))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM