Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing 如何在clojure中模拟宏进行测试?_Unit Testing_Clojure_Macros - Fatal编程技术网

Unit testing 如何在clojure中模拟宏进行测试?

Unit testing 如何在clojure中模拟宏进行测试?,unit-testing,clojure,macros,Unit Testing,Clojure,Macros,我想模拟命名空间中的宏 例如,clojure.tools.logging/error 我用redefs尝试了,但运气不好 (def logged false) (defmacro testerror {:arglists '([message & more] [throwable message & more])} [& args] `(def logged true)) (deftest foo ... (with-redefs [log

我想模拟命名空间中的宏

例如,
clojure.tools.logging/error

我用redefs尝试了
,但运气不好

(def logged false)

(defmacro testerror
  {:arglists '([message & more] [throwable message & more])}
  [& args]
  `(def logged true))

(deftest foo
 ...
 (with-redefs
      [log/error testerror]
   ...
这就产生了这个错误:
compilereException java.lang.RuntimeException:无法获取宏的值

您不能这样做。宏的意义在于,在编译代码时它们会被扩展,然后它们就消失了。包含宏调用的原始代码不可恢复。无法在运行时追溯重新定义宏:已经太晚了


如果您想要有可交换的日志记录实现,另一种方法是使用类似组件的东西进行依赖项注入,并根据您是在运行测试还是在运行实际程序,使用不同的日志记录组件。可以说这有点过分,也许有一个更简单的方法,但我不知道

Amalloy为您提供了关于如何模拟宏的直接问题的答案—您不能

但是,您可以使用其他解决方案解决您的问题(比将整个应用程序移动到组件依赖项注入更简单)。让我建议两种替代实现(不幸的是,这不是很简单,但仍然比使用组件更简单)

模拟日志宏调用的函数 不能模拟宏,但可以模拟日志宏展开时将使用的函数

(require '[clojure.tools.logging :as log])
(require '[clojure.pprint :refer [pprint]])

(pprint (macroexpand `(log/error (Exception. "Boom") "There was a failure")))
给出:

(let*
 [logger__739__auto__
  (clojure.tools.logging.impl/get-logger
   clojure.tools.logging/*logger-factory*
   #object[clojure.lang.Namespace 0x2c50fafc "boot.user"])]
 (if
  (clojure.tools.logging.impl/enabled? logger__739__auto__ :error)
  (clojure.core/let
   [x__740__auto__ (java.lang.Exception. "Boom")]
   (if
    (clojure.core/instance? java.lang.Throwable x__740__auto__)
    (clojure.tools.logging/log*
     logger__739__auto__
     :error
     x__740__auto__
     (clojure.core/print-str "There was a failure"))
    (clojure.tools.logging/log*
     logger__739__auto__
     :error
     nil
     (clojure.core/print-str x__740__auto__ "There was a failure"))))))
如您所见,执行实际日志记录的函数(如果启用了给定级别)是通过
clojure.tools.logging/log*
函数完成的

我们可以模拟它并编写测试:

(require '[clojure.test :refer :all])

(def log-messages (atom []))

(defn log*-mock [logger level throwable message]
  (swap! log-messages conj {:logger logger :level level :throwable throwable :message message}))

(with-redefs [clojure.tools.logging/log* log*-mock]
  (let [ex (Exception. "Boom")]
    (log/error ex "There was a failure")
    (let [logged (first @log-messages)]
      (is (= :error (:level logged)))
      (is (= "There was a failure!" (:message logged)))
      (is (= ex (:throwable logged))))))
使用日志库API收集和检查日志消息
您的日志库API可能提供一些特性,允许您插入测试以收集和断言日志事件。例如,您可以编写自己的实现,以收集所有记录的日志记录和。

您是否试图使日志消息短路?看起来你可以用一个函数来代替一个宏…你能解释一下你为什么要模拟它吗?这可能有助于为您的问题提供替代解决方案()@PiotrekBzdyl我想测试是否记录了捕获到的异常。@Alan Thompson谢谢,这是可行的。组件有点改变了您的生活方式,虽然已经使用了6个月,但到目前为止还是值得的。总的来说,我支持这个建议,因为在这个过程中会遇到很多其他问题。在许多项目中,这也完全是多余的。我经常使用组件,但如果您需要的话,您可以使用更小的依赖项注入。