使用Mockito.doAnswer(...)重复答案处理

时间:2017-10-30 12:39:34

标签: java unit-testing logging mockito powermockito

我正在尝试测试一个静态方法,该方法捕获来自不同子调用或方法本身的异常,并且只记录异常消息。根据要求,我无法改变方法实现。在这种情况下,间谍子调用不是一个选项,因为我们希望在测试中保持一致,并且由于一些执行从方法体本身抛出异常,我们最终选择检查...错误日志消息。 < / p>

因此,我想模拟将从方法调用的记录器,当记录器调用与特定消息匹配的错误(...)时,添加记录调用的答案。到目前为止在我身边这么好。我所做的一个例子如下:

Mockito.doAnswer(new Answer<Void>()
{
    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        String errorMessage = (String) args[0];
        assertTrue(errorMessage.contains(SPECIFIC_MESSAGE));
        return null;
    }
}).when(logger).error(Matchers.startsWith(GENERIC_PREFIX));

我们决定使用PowerMockito来模拟静态调用,并从LoggerFactory.getLogger(...)返回我们的模拟记录器

Logger logger = Mockito.mock(Logger.class); 
PowerMockito.mockStatic(LoggerFactory.class);
Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);

现在出现了我们的问题:

对于每个测试,要检查更改的消息SPECIFIC_MESSAGE的值。因此,我们为每个测试模拟一个记录器,模拟静态LoggerFactory调用以返回记录器,然后将我们的特定答案添加到我们对此特定实例的logger.error(...)调用中。但在我们的第一次测试中添加到logger.error调用的第一个答案似乎覆盖了所有其他答案。每次测试都会发生相同的执行。

我认为这个问题可能来自Mockito会返回单身模拟,但我测试了它并且情况并非如此。然后我认为我的问题可能来自我的LoggerFactory.getLogger(...)调用,它会一直返回记录器的同一个实例但不是这种情况。这是一个实现,它显示了我的代码与相关执行日志跟踪相同的问题。

import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App
{
    public static Logger logger = LoggerFactory.getLogger(App.class);

    public static void main(String[] args)
    {
        logger.error("Error = " + Arrays.toString(args));
    }
}

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest({LoggerFactory.class})
public class AppTest
{
    @Test
    public void firstTest()
    {
        Logger logger = Mockito.mock(Logger.class); 
        PowerMockito.mockStatic(LoggerFactory.class);
        Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);

        Mockito.doAnswer(new Answer<Void>()
        {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String errorMessage = (String) args[0];
                System.out.println("Calling from firstTest");
                assertTrue(errorMessage.contains("a"));
                return null;
            }
        }).when(logger).error(Matchers.startsWith("Error"));

        App.main(new String[]{ "a" });
    }

    @Test
    public void secondTest()
    {
        Logger logger = Mockito.mock(Logger.class); 
        PowerMockito.mockStatic(LoggerFactory.class);
        Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);

        Mockito.doAnswer(new Answer<Void>()
        {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String errorMessage = (String) args[0];
                System.out.println("Calling from secondTest");
                assertTrue(errorMessage.contains("b"));
                return null;
            }
        }).when(logger).error(Matchers.startsWith("Error"));

        App.main(new String[]{ "b" });
    }
}

TRACE:

Calling from firstTest
Calling from firstTest

知道为什么第二个答案没有处理?提前谢谢。

修改

问题实际上来自静态方法mock。 &#34;然后我认为我的问题可能来自我的LoggerFactory.getLogger(...)调用,它会一直返回记录器的同一个实例,但也不会返回。&#34;实际上是错的。它在我的测试中是有效的,其中调用getLogger(...)返回在测试中被模拟的记录器模拟,但是当实际调用App.main(...)方法时,在main中调用模拟的getLogger(...)方法(...)始终返回相同的实例,并且不会按预期在测试之间重置。 Mockito应该在每个文档的测试之间重置。一个mockito的bug或限制?与Mockito和PowerMockito之间的互动有关的麻烦?

1 个答案:

答案 0 :(得分:0)

我找到了一个解决方案,即在每个测试的方法级别为类静态模拟做准备。 在签名之前添加@PrepareForTest(LoggerFactory.class)实际上解决了在测试之间没有重置记录器工厂模拟的问题,因此第一个调用Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);始终有效并始终返回相同的记录器。