我正在尝试测试一个静态方法,该方法捕获来自不同子调用或方法本身的异常,并且只记录异常消息。根据要求,我无法改变方法实现。在这种情况下,间谍子调用不是一个选项,因为我们希望在测试中保持一致,并且由于一些执行从方法体本身抛出异常,我们最终选择检查...错误日志消息。 < / 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之间的互动有关的麻烦?
答案 0 :(得分:0)
我找到了一个解决方案,即在每个测试的方法级别为类静态模拟做准备。
在签名之前添加@PrepareForTest(LoggerFactory.class)
实际上解决了在测试之间没有重置记录器工厂模拟的问题,因此第一个调用Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);
始终有效并始终返回相同的记录器。