【问题标题】:Mocking logger in Play! 2 Framework在 Play 中模拟记录器! 2 框架
【发布时间】:2012-08-29 16:55:33
【问题描述】:

我有戏! 2 应用程序(Scala),并且我有一些类在遇到错误时需要执行日志记录。

我希望能够对这些日志记录操作实际发生在正确的条件下进行单元测试。为此,我需要能够模拟记录器,但我遇到了 Mockito 的一些问题。我所拥有的(简化的)看起来像

import play.api.{ Logger, LoggerLike }

trait BaseService {
  val log: LoggerLike

  def fail(reason: String) {
    log.error(reason)
   }
}

object Service extends BaseService {
  val log = Logger
}

然后在测试中

import org.specs2.mutable._
import org.specs2.mock._
import services.BaseService

object Service extends BaseService with Mockito {
  val log = mock[play.api.Logger]

  def verify(key: String) = {
    there was one(log).error(key)
  }
}

class ServiceSpec extends Specification {
  "failures should be logged" in {
    Service.fail("foo")
    Service.verify("foo")
  }
}

但我得到了错误

[error]     NullPointerException: null (Logger.scala:43)
[error] play.api.LoggerLike$class.isErrorEnabled(Logger.scala:43)
[error] play.api.Logger.isErrorEnabled(Logger.scala:147)
[error] play.api.LoggerLike$class.error(Logger.scala:127)
[error] play.api.Logger.error(Logger.scala:147)
[error] services.BaseService$class.fail(Service.scala:19)
[error] Service$.fail(ServiceSpec.scala:11)
...

我尝试添加

log.isErrorEnabled returns true
log.error(any[String]) returns {}

然后连Service的初始化都失败了。

【问题讨论】:

    标签: unit-testing scala mocking playframework-2.0 mockito


    【解决方案1】:

    我不是 Mockito 专家,但我认为您的 mock 在这里出现故障,因为堆栈跟踪显示了正在调用的实际播放 Logger 方法。这可能是因为您试图在此处模拟 Scala object。相反,如果您像

    那样模拟特征
     val log = mock[play.api.LoggerLike]
    

    您将克服这个特定错误并进入下一个问题 - 您的验证不起作用:

    [error]   The mock was not called as expected: 
    [error] Argument(s) are different! Wanted:
    [error] loggerLike.error(
    [error]     ($anonfun$apply$mcV$sp$1) <function0>
    [error] );
    [error] -> at Service$$anonfun$verify$1.apply$mcV$sp(ServiceSpec.scala:10)
    [error] Actual invocation has different arguments:
    [error] loggerLike.error(
    [error]     ($anonfun$fail$1) <function0>
    [error] );
    [error] -> at services.BaseService$class.fail(x.scala:57)
    [error]  (ServiceSpec.scala:17)
    

    这是由于日志消息作为按名称参数(因此是匿名函数)而不是字符串传递的事实引起的,请参阅this question 以获取进一步讨论。

    【讨论】:

    • 谢谢,这正是问题所在!现在仍有待清除如何解决 pass-by-name。您发布的问题中的解决方案看起来有点难看,但希望我能够将它按摩成更清晰的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多