如何在 Junit 中使用 slf4j 模拟 log4j2 记录器对象

Posted

技术标签:

【中文标题】如何在 Junit 中使用 slf4j 模拟 log4j2 记录器对象【英文标题】:How to mock log4j2 logger object using slf4j in Junit 【发布时间】:2018-07-31 13:41:03 【问题描述】:

我在下面的代码中使用 slf4j 工厂创建不同的 log4j2 记录器对象,我需要根据输入参数写入特定的日志文件。

@Service
class WriterService 

val logger1: Logger = LoggerFactory.getLogger("t_logger")
val logger2: Logger = LoggerFactory.getLogger("b_logger")
val labelKey = "Label"

fun writeLog(payload: Map<String, Any>)

    if(payload.containsKey(labelKey)) 

        val label = payload[labelKey].toString().toLowerCase()

        if (label == "t") 
            logger1.info("", payload)

         else if (label == "b") 
            logger2.info("", payload)
        
    

我想知道如何使用 MockitoJUnitRunner 模拟 Logger 对象,以便模拟调用了哪个记录器对象?

【问题讨论】:

【参考方案1】:

我找到了使用 Appender 和 ArgumentCaptor 的解决方案... 下面的解决方案供可能感兴趣的人使用...

import org.apache.logging.log4j.Level
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.core.Appender
import org.apache.logging.log4j.core.LogEvent
import org.apache.logging.log4j.core.Logger
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.runners.MockitoJUnitRunner
import java.lang.StringBuilder

@RunWith(MockitoJUnitRunner::class)
class ServiceTest 

    @InjectMocks
    var service: WriterService 

    @Mock
    private val mockAppender: Appender? = null

    @Captor
    private val captorLoggingEvent: ArgumentCaptor<LogEvent>? = null

    private var logger1: Logger? = null
    private var logger2: Logger? = null

    @Before
    fun setup() 
        `when`(mockAppender!!.name).thenReturn("MockAppender")
        `when`(mockAppender.isStarted).thenReturn(true)
        `when`(mockAppender.isStopped).thenReturn(false)

        logger1 = LogManager.getLogger("t_logger") as Logger
        logger1!!.addAppender(mockAppender)
        logger1!!.level = Level.INFO

        logger2 = LogManager.getLogger("b_logger") as Logger
        logger2!!.addAppender(mockAppender)
        logger2!!.level = Level.INFO
    

    @After
    fun tearDown() 
        logger1!!.removeAppender(mockAppender!!)
        logger2!!.removeAppender(mockAppender!!)
    

    @Test
    fun writeLog_shouldWriteTransactionLogWhenLabelIs_T() 

        val payload = hashMapOf("Label" to "t")

        service.writeLog(payload)

        verify(mockAppender, times(1))!!.append(captorLoggingEvent!!.capture())
        assertEquals(captorLoggingEvent.value.level, Level.INFO)
        assertEquals(captorLoggingEvent.value.loggerName, "t_logger")
        assertEquals(captorLoggingEvent.value.message.formattedMessage, "Label=t")
    

    @Test
    fun writeLog_shouldWriteBackendLogWhenLabelIs_B() 

        val payload = hashMapOf("Label" to "b")

        service.writeLog(payload)

        verify(mockAppender, times(1))!!.append(captorLoggingEvent!!.capture())
        assertEquals(captorLoggingEvent.value.level, Level.INFO)
        assertEquals(captorLoggingEvent.value.loggerName, "b_logger")
        assertEquals(captorLoggingEvent.value.message.formattedMessage, "Label=b")
    

【讨论】:

以上是关于如何在 Junit 中使用 slf4j 模拟 log4j2 记录器对象的主要内容,如果未能解决你的问题,请参考以下文章

在 Intellij idea Ultimate2017.2 中运行 maven webapp 时出错:原因:java.lang.NoClassDefFoundError: Lorg/slf4j/Lo

Spring JUnit:如何在自动装配组件中模拟自动装配组件

如何在JUnit测试中模拟Camel处理器

如何使用 JUnit、EasyMock 或 PowerMock 模拟静态最终变量

如何在 JUnit5 中使用 Mockito

如何模拟JPA Repository以使用它与Junit进行测试?