2013-07-18 12 views
9

Qui ho un piccolo problema e non ho davvero idea di come implementare il test dell'unità per i messaggi del logger. Certo, suona un po 'strano, ma per me è un argomento davvero interessante. Ma lasciami essere più specifico.Messaggi logger test unità utilizzando specs2 + scalalogging

Ho un po 'di classe Scala e prova specifica:

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")? 
    } 
    } 
} 

Il mio primo pensiero è stato quello di intercettare i messaggi del motore logger sottostanti ma sembra un po' cosa difficile da attuare a causa di utilizzo di mixins in classe testabile, quindi ogni le idee per fare queste cose sarebbero molto utili.

UPDATE: Ho finalmente implementato un test e ho deciso di condividere la mia soluzione con la comunità. Non possiamo prendere in giro la classe scalalogging.Logger direttamente perché è definitiva, ma possiamo ancora prendere in giro sottotitoli slf4j. Per chiarire un'idea:

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") 
     } 
    } 
} 

Grazie Eric per il suo aiuto. La sua risposta è stata una chiave per la soluzione.

risposta

4

Una possibilità è quella di utilizzare Mockito per controllare le chiamate di metodo:

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") 
    } 
    } 
} 

Questa è l'idea principale, ma potrebbe essere necessario adattarlo in base alle proprie caratteristiche esatte e quadro di registrazione:

  • logger deve essere Overridable
  • il metodo di informazioni non deve essere definitiva (una delle limitazioni di Mockito)
+0

Eric, sembra il modo di andare, grazie! Almeno non richiede alcuna modifica nella classe Testable. –

0

Buona domanda ... e buona risposta! Ho avuto qualche problema con il mixaggio di Mockito. Quindi sto usando l'approccio di Eric con Java DSL per Mockito. Se qualcuno è interessato a questa variazione, ecco il codice leggermente modificato:

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") 
    } 
}