我有两个班,第一个班:
public class FirstClass {
private static final Logger LOG = Logger.getLogger(FirstClass.class);
public void action(){
LOG.info("FirstClass.action.");
}
}
第二课:
public class SecondClass {
private static final Logger LOG = Logger.getLogger(SecondClass.class);
public void action(){
FirstClass firstClass = new FirstClass();
firstClass.action();
}
}
我将为这两个类编写单元测试,即第一类单元测试:
public class FirstClassTest {
@Test
public void testAction(){
FirstClass firstClass = new FirstClass();
firstClass.action();
}
}
第二类单元测试:
public class SecondClassTest {
@Mocked
private Logger LOG;
@Mocked
private FirstClass firstClass;
@Test
public void testAction(){
SecondClass secondClass = new SecondClass();
secondClass.action();
}
}
关于第二类单元测试,由于第二类依赖于第一类,所以我嘲笑了第一个类,同时我也嘲笑了Logger类。
我添加了一个套件类来运行这两个类:
@RunWith(Suite.class)
@Suite.SuiteClasses({SecondClassTest.class ,FirstClassTest.class})
public class TestAll {
}
当我运行这个套件类时,它抛出以下异常:
java.lang.NullPointerException
at org.apache.log4j.Category.info(Category.java:663)
at steve.test.jmockit.issues.mocklog4j.FirstClass.action(FirstClass.java:12)
at steve.test.jmockit.issues.mocklog4j.FirstClassTest.testAction(FirstClassTest.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
从此跟踪日志中,已经模拟了第一类的LOG。但实际上我并没有在FirstClassTest类中模拟Logger。
但是当我改变这个套件类时,首先运行FirstClassTest.class,然后运行SecondClassTest.class。所有案例都是成功的。
@RunWith(Suite.class)
@Suite.SuiteClasses({FirstClassTest.class ,SecondClassTest.class})
public class TestAll {
}
如何解决此问题并确保两种情况之间没有影响?谢谢!
答案 0 :(得分:1)
发生异常是因为两个测试都在相同的 LOG.info(...)
实例上调用LOG
,这是未初始化的实例(即实例)及其所有参考字段null
)。
LOG
持有未初始化实例的原因是Logger
类在执行第一个测试时被模拟。在第二次测试运行之前,类会被取消模拟,但这不会更改LOG
对象的状态。因此,当第二次调用LOG.info(...)
时,它不会被模拟,而是尝试使用仍然Logger
的{{1}}字段,从而导致NPE。
避免此问题的方法是确保在null
类被模拟之前初始化LOG
字段。例如,可以通过添加Logger
实例化@BeforeClass
的方法(因为它包含有问题的FirstClass
字段)来完成此操作。
答案 1 :(得分:0)
我运行了第一个套件,但没有看到您描述的问题。我的输出是:
Jul 09, 2015 12:00:59 AM First action
INFO: FirstClass.action.
我正在使用JMockit 1.18; JDK 1.8; JUnit 4.12