使用 Midje 测试音色日志输出

Testing Timbre log outputs with Midje

我正在使用 Timbre as a logging library but I am having issues testing it with Midje。我有以下方法,我想做的就是断言 Will be printed 已打印。

(defn init [level]
    (timbre/merge-config! {:output-fn my-output-fn})
    (timbre/set-level! level)
    (timbre/info "Will be printed")
    (timbre/debug "Won't be printed"))

通过将 (timbre/default-output-fn) 包装在我自己的函数 my-output-fn 周围,我可以断言只打印了 2 条日志中的 1 条,这是正确的:

(fact "print info but not debug"
    (core/init :info) => nil
    (provided
        (core/my-output-fn anything) => irrelevant :times 1))

但是我想确保正在打印的消息是 Will be printed。我找不到任何方法,你会怎么做?

我在下面的项目中做实验https://github.com/stephanebruckert/timbre-midje

可以使用 Midje 的 as-checker prerequisite.

验证函数的输入

当您打印进入 timbre/default-output-fndata 时(我通过您的 output-fn 发现了这一点),您会看到它具有以下结构:

{:hash_ #delay[{:status :pending, :val nil} 0x5ed805b1], :instant #inst "2016-10-14T17:07:16.779-00:00", :config {:level :info, ....

因此日志级别在 data 中可用。使用 as-checker 可以按如下方式验证 log level

(fact "print info but not debug"
      (core/init :info) => nil
      (provided
       (timbre/default-output-fn anything ; opts is first argument
                                 (as-checker (fn [data]
                                               (= (-> data :config :level) ; get log level
                                                  :info))))     ; validate that it is info
       => anything :times 1)
      (provided
       (timbre/default-output-fn anything
                                 (as-checker (fn [data]
                                               (= (-> data :config :level)
                                                  :debug))))
       => anything :times 0))

现在,您想查看邮件的内容。不仅是日志级别。

实际消息在传递给 default-output-fnoptsdata 中不可用。环顾 Timbre 代码,我看到它在一个私有函数 vargs->margs 中可用,该函数接受一个 ?err、一个 msg-typevargsvargs 包含消息(在您的情况下,例如 :auto :p ["The message"]).

通过 as-checker 方法可以验证消息如下:

(fact "print Will be printed, not Won't be printed"
      (core/init :info) => nil
      (provided
       (#'timbre/vargs->margs anything anything ["Will be printed"]) => {} :times 1)
      (provided
       (#'timbre/vargs->margs anything anything ["Won't be printed"]) => {} :times 0) )

注意 vargs->margs 必须 return 映射,否则 Timbre 会在后面的函数中抛出异常。

这样可以验证 "Will be printed" 被打印一次,而 "Won't be printed" 永远不会被打印。

@ErwinRooijakkers 的想法可行,但 @ptaoussanis on Github 有充分的理由不这样做。

Please note that timbre/vargs->margs is private, and an implementation detail. Its behaviour can change at any time without notice, would strongly recommend not depending on it in any way.

It'd be possible to use a custom appender that sends output somewhere that are handy for your tests to analyse. You could setup these appenders as part of your test setup, and/or use something like timbre/with-config for the appropriate test calls.

所以我们可以添加一个 appender 来传递参数以检查 (level message) 到存根。

core.clj

(defn init
  ([level]
    (init level {}))
  ([level config]
    (timbre/merge-config! config)
    (timbre/set-level! level)
    (timbre/info "will be printed")
    (timbre/debug "won't be printed")))

core_test.clj

(:require [timbre-midje.core :as core]
          [midje.sweet :refer :all]))

(defn log-stub [level message])

(def log-stub-appender
  {:appenders
    {:test-appender
      {:enabled? true
       :fn (fn [data] (log-stub (:level data) (:vargs data)))}}})

(fact "print info but not debug"
  (core/init :info log-stub-appender) => nil
  (provided
    (log-stub :info ["will be printed"]) => irrelevant :times 1
    (log-stub :debug ["won't be printed"]) => irrelevant :times 0))