2013-07-18 38 views
9

我在這裏有一個小問題,真的不知道如何實現記錄器消息的單元測試。當然,這聽起來有點不可思議,但對我來說這真的很有趣。但讓我更具體。使用specs2 + scalalogging的單元測試記錄器消息

我有一些Scala的類和測試規範:

class Testable extends Logging { 
    def method() = { 
    // some method calls 
    logger.info("Message1") 
    } 
} 

class TestableSpec extends Specification with ShouldMatchers with Mockito { 
    "Testable instance" should { 
    // some important tests 

    "print proper log message during method call" in { 
     // And how to test that logger really prints proper message ("Message1")? 
    } 
    } 
} 

我首先想到的是攔截潛在的記錄引擎發出的消息,但似乎是由於可測類混入的使用,以實現硬一點的東西,因此任何做這種事情的想法會很有幫助。

更新: 我終於實現了一個測試,並決定與社區分享我的解決方案。我們不能直接模擬scalalogging.Logger類,因爲它是最終的,但我們仍然可以模擬潛在的slf4j Logger。澄清一個想法:

class Testable extends Logging { 
    def foo() = { 
     // ... 
     logger.info("Foo has been called") 
    } 
} 

// Another imports are omitted. 
import com.typesafe.scalalogging.slf4j.Logger 
import org.slf4j.{Logger => Underlying} 

class TestableSpec extends Specification with Mockito with ShouldMatchers { 
    def initTestable(mocked: Underlying): Testable = { 
     new Testable() { 
      override lazy val logger = Logger(mocked) 
     } 
    } 

    "Testable instance" should { 
     "invoke logger with a proper message" in { 
      val mocked = mock[Underlying] 
      mocked.isInfoEnabled returns true // Should be set to true for test 
      initTestable(mocked).foo() 

      there was one(mocked).info("Foo has been called") 
     } 
    } 
} 

感謝Eric的幫助。他的回答是解決方案的關鍵。

回答

4

一種可能是使用的Mockito檢查方法調用:

class Testable extends Logging { 
    def method() = { 
    // some method calls 
    logger.info("Message1") 
    } 
} 

class TestableSpec extends Specification with ShouldMatchers with Mockito { 
    "Testable instance" should { 
    "print proper log message during method call" in { 
     val mockLogger = mock[Logger] 
     val testable = new Testable { 
     // switch the logger with a mock instance 
     override val logger = mockLogger 
     } 
     testable.method() 
     there was one(mockLogger).info("Message1") 
    } 
    } 
} 

這是主要的想法,但你可能會根據您的具體特點和日誌框架,以適應它:

  • 記錄儀必須被覆蓋
  • 信息方法不能是最終的(Mockito的限制之一)
+0

埃裏克,它看起來像要走的路,謝謝!至少它不需要對Testable類進行任何更改。 –

0

很好的問題...和很好的答案!我在Mockito混搭中遇到了一些麻煩。因此,我正在使用Eric的Java方法來處理Mockito。如果任何人對這個變化感興趣,這裏是稍微修改的代碼:

import com.typesafe.scalalogging.{LazyLogging, Logger, StrictLogging} 
import org.mockito.Mockito 
import org.mockito.Mockito._ 
import org.slf4j.{Logger => Underlying} 

class Testable extends LazyLogging { 
    def foo() = { 
    logger.info("Foo has been called") 
    } 
} 

import org.junit.runner.RunWith 
import org.scalatest.{BeforeAndAfterEach, FunSuite} 
import org.scalatest.junit.JUnitRunner 
import org.scalatest.matchers.ShouldMatchers 


@RunWith(classOf[JUnitRunner]) 
class LoggerTest 
    extends FunSuite with ShouldMatchers with BeforeAndAfterEach { 


    def initTestable(mocked: Underlying): Testable = { 
    new Testable() { 
     override lazy val logger = Logger(mocked) 
    } 
    } 

    test("the mockito stuff") { 
    val mocked = Mockito.mock(classOf[Underlying]) 
    when(mocked.isInfoEnabled()).thenReturn(true) 
    initTestable(mocked).foo() 
    verify(mocked).info("Foo has been called") 
    } 
}