如何在 Clojure 测试中测试预期异常的消息?

How to test the message of an expected exception in a Clojure test?

我有以下 Clojure 代码:

(defn is-valid-lang
  [lang]
  (.contains (list "ru" "en" "de") lang))

(defn s
  [txt]
  {
   :desc txt
   :lang "ru"
   })

(defn s
  [txt lang]
  (if-not (is-valid-lang lang)
    (throw (.IllegalArgumentException (format "'%s' is an invalid language." lang)))
    {
     :desc txt
     :lang lang
     }
    )
  )

我想编写一个测试来验证 s 抛出的异常消息,如果 lang 无效。

我写了这个:

(deftest s-lang-invalid-lang-test
  (is
    (thrown-with-msg?
      IllegalArgumentException
      #"'invalid-language' is an invalid language."
      (s "something" "invalid-language")
      )
    )
  )

由于以下错误,测试失败:

error {
 :cause "No matching field found: IllegalArgumentException for class java.lang.String"
 :via
 [{:type java.lang.IllegalArgumentException
   :message "No matching field found: IllegalArgumentException for class java.lang.String"
   :at [clojure.lang.Reflector getInstanceField "Reflector.java" 397]}]
 :trace

如果 s 抛出异常并显示正确消息,我该如何解决此问题并确保测试成功?

更新 1: 修复了 cfrick 指出的多参数问题。

(defn s
  ([txt]
   {
    :desc txt
    :lang "ru"
    })
  ([txt lang]
   (if-not (is-valid-lang lang)
     (throw (IllegalArgumentException. (format "'%s' is an invalid language." lang)))
     {
      :desc txt
      :lang lang
      })
   )
  )

您没有正确实例化 IllegalArgumentException。 Clojure 使用:

(IllegalArgumentException. "your message")

调用Java构造函数。参见 this article on Java interop

作为替代技术,您可以使用正则表达式搜索异常错误消息,如下所示:

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(defn thrower
  [lang]
  (throw (ex-info "invalid language" {:lang lang})))

(dotest
  (throws? (thrower "bogosity")) ; just verify it throws an exception, ignoring type and message
    ; `(throws? ...)` is a convenience fn from tupelo.test (also `dotest`)

  (try
    (thrower "bogosity")
    (catch Exception e
      (let [s (str e)]
        (is (re-find #"invalid language" s)) ; returns "invalid language"
        (is (re-find #"bogosity" s)))        ; returns "bogosity"
      )))

在单元测试中,搜索预期的字符串片段(例如异常错误消息中的 in)通常比进行字符串相等性比较更容易。完整的异常字符串是:

clojure.lang.ExceptionInfo: invalid language {:lang "bogosity"}

为了方便,我们使用tupelo.test library。函数 is-nonblank= 也很方便。

tupelo.string开始,我们还有这些辅助函数:

  • 小写=
  • 非空行=
  • 非空白=
  • 包含匹配项?
  • 包含-str?
  • 引用->单
  • 引号->双

以及许多其他使编写基于字符串的测试变得更加容易的方法。