Testing thrown ex-info exceptions

Note that thrown? and thrown-with-msg? are two default implementations of the clojure.test/assert-expr multimethod. You can make an implementation for handling clojure.lang.ExceptionInfo or the CLJS equivalent. This is a straightforward implementation that compares the data, but you probably want to make this check for sub-maps (does the data you expect occur in the data returned).

(require '[clojure.test :as t :refer [deftest is do-report]])

(defmethod t/assert-expr 'thrown-with-data? [msg form]
  (let [data (second form)
        body (nthnext form 2)]
    `(try ~@body
          (do-report {:type :fail, :message ~msg,
                      :expected '~form, :actual nil})
          (catch clojure.lang.ExceptionInfo e#
            (let [expected# ~data
                  actual# (ex-data e#)]
              (if (= expected# actual#)
                (do-report {:type :pass, :message ~msg,
                            :expected expected#, :actual actual#})
                (do-report {:type :fail, :message ~msg,
                            :expected expected#, :actual actual#})))
            e#))))

(deftest foo
  (is (thrown-with-data? {:a 1} (throw (ex-info "" {:a 1}))))
  (is (thrown-with-data? {:b 1} (throw (ex-info "" {:a 1})))))

(t/run-tests) 
$ clj /tmp/test.clj

Testing user

FAIL in (foo) (test.clj:24)
expected: {:b 1}
  actual: {:a 1}

Ran 1 tests containing 2 assertions.
1 failures, 0 errors.

Bonus, also works in babashka:

$ bb /tmp/test.clj

Testing user

FAIL in (foo) (/private/tmp/test.clj:22)
expected: {:b 1}
  actual: {:a 1}

Ran 1 tests containing 2 assertions.
1 failures, 0 errors.
{:test 1, :pass 1, :fail 1, :error 0, :type :summary}
14 Likes