播放2.6 [Scala]:如何在测试期间访问日志内容?

时间:2018-02-27 10:30:57

标签: logging playframework logback slf4j scalatest

假设我有一条触发/log控制器方法的路由MyController.iDoLogSometimes

class MyController extends Controller{
  def iDoLogSometimes = Action{
    request => 
     val hasProperty: Boolean = ??? //A request property check
     if(hasProperty) Logger.info("prop exist")
     else Logger.debug("prop does not exist")   
  }
}

现在,在测试中,我可以发送FakeRequest我需要的任何属性;在我的方法中涵盖这两种情况。 但是我不知道如何捕获Logger输出并使用某种must匹配器。

请注意我的logback.xml文件夹中有conf/;我确实在控制台中看到了日志;在测试过程中。

1 个答案:

答案 0 :(得分:2)

使用大多数Java / Scala日志库可靠地捕获日志输出并不容易,因为日志是全局的,并且访问是并发的。 然而,如果你愿意,你可以试一试。我最近在Play test做了这个。我使用的是specs2而不是scalatest,但捕获日志的想法是一样的:

import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.AppenderBase
import org.slf4j.LoggerFactory
...
"not complain about invalid User-Agent headers" in {

  // This test modifies the global (!) logger to capture log messages.
  // The test will not be reliable when run concurrently. However, since
  // we're checking for the *absence* of log messages the worst thing
  // that will happen is that the test will pass when it should fail. We
  // should not get spurious failures which would cause our CI testing
  // to fail. I think it's still worth including this test because it
  // will still often report correct failures, even if it's not perfect.

  import scala.collection.immutable

  def recordLogEvents[T](block: => T): immutable.Seq[ILoggingEvent] = {

    /** Collects all log events that occur */
    class RecordingAppender extends AppenderBase[ILoggingEvent] {
      private val eventBuffer = ArrayBuffer[ILoggingEvent]()
      override def append(e: ILoggingEvent): Unit = synchronized {
        eventBuffer += e
      }
      def events: immutable.Seq[ILoggingEvent] = synchronized {
        eventBuffer.to[immutable.Seq]
      }
    }

    // Get the Logback root logger and attach a RecordingAppender
    val rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME).asInstanceOf[Logger]
    val appender = new RecordingAppender()
    appender.setContext(rootLogger.getLoggerContext)
    appender.start()
    rootLogger.addAppender(appender)
    block
    rootLogger.detachAppender(appender)
    appender.stop()
    appender.events
  }

  withServerAndConfig()((Action, _) => Action { rh =>
    Results.Ok(rh.headers.get("User-Agent").toString)
  }) { port =>
    def testAgent[R: AsResult](agent: String) = {
      val logMessages = recordLogEvents {
        val Seq(response) = BasicHttpClient.makeRequests(port)(
          BasicRequest("GET", "/", "HTTP/1.1", Map(
            "User-Agent" -> agent
          ), "")
        )
        response.body must beLeft(s"Some($agent)")
      }
      logMessages.map(_.getFormattedMessage) must contain(contain(agent))
    }
    // These agent strings come from https://github.com/playframework/playframework/issues/7997
    testAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0_3 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Mobile/15A432 [FBAN/FBIOS;FBAV/147.0.0.46.81;FBBV/76961488;FBDV/iPhone8,1;FBMD/iPhone;FBSN/iOS;FBSV/11.0.3;FBSS/2;FBCR/T-Mobile.pl;FBID/phone;FBLC/pl_PL;FBOP/5;FBRV/0]")
    testAgent("Mozilla/5.0 (Linux; Android 7.0; TRT-LX1 Build/HUAWEITRT-LX1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/148.0.0.51.62;]")
    testAgent("Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 [FB_IAB/Orca-Android;FBAV/142.0.0.18.63;]")
  }

}