我正在尝试编写测试以确保我是否正在调用enum的方法但是收到错误:
@RunWith(PowerMockRunner.class)
@PrepareForTest({MonitorTask.class})
public class MonitorTest {
@Test
public void initialize() {
MonitorTask mockInstance = mock(MonitorTask.class);
Whitebox.setInternalState(MonitorTask.class, "TIMER", mockInstance);
Mockito.spy(mockInstance.initialize());
}
}
这是我要测试的课程
public class Monitor {
public boolean initialize() {
return MonitorTask.TIMER.initialize();
}
}
ENUM:
public enum MonitorTask {
TIMER;
private final AtomicBoolean isPublishing = new AtomicBoolean(false);
private final long period = ConfigUtils
.requireLong("getMonitor");
public synchronized boolean initialize() {
return initialize(period, period);
}
boolean initialize(long delay, long period) {
if (isPublishing.get()) {
return false;
}
TimerTask task = new TimerTask() {
@Override public void run() {
try {
Publisher.INSTANCE.update(DateTime.now());
} catch (Exception e) {
log.warn("Exception", e);
}
}
};
Timer timer = new Timer("MonitorTask", true);
timer.schedule(task, delay, period);
isPublishing.set(true);
return true;
}
}
有人可以告诉我,我的测试有什么问题吗? 我得到的错误:
java.lang.ExceptionInInitializerError at sun.reflect.GeneratedSerializationConstructorAccessor8.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45) at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73) 在org.mockito.internal.creation.jmock.ClassImposterizer.createProxy(未知来源) 在org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(未知来源) 在org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(未知来源) 在org.mockito.internal.creation.CglibMockMaker.createMock(未知来源) 在org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:43) 在org.mockito.internal.util.MockUtil.createMock(未知来源) 在org.mockito.internal.MockitoCore.mock(未知来源) 在org.mockito.Mockito.mock(未知来源) 在org.mockito.Mockito.mock(未知来源)
答案 0 :(得分:0)
首先:枚举常量表示为内部类,因此@PrepareForTest注释必须与内部类的类名一起使用 - 请参阅{{3进一步阅读。
除此之外:我喜欢使用枚举这样的"单身"对象也是。但使用PowerMock测试它们是错误的答案。 PowerMock依赖于字节代码操作(以避免这些枚举类是最终的,因此无法被静默覆盖)。而且严重的是:PowerMock和他的其他权力兄弟会带来更多麻烦而不是好事。我花了无数个小时来寻找奇怪的问题,从来没有在我的代码中找到错误。直截了当:使用PowerMock时,您可以忘记进行覆盖率测量。
我的解决方案"附带了更多的代码,但它允许测试而无需转向PowerMock ......
首先将所需的功能放入界面:
class TimerInitializationImpl implements TimerInitialization { ...
然后创建一个实现接口的普通类:
public enum MonitorTask implements TimerInitialization {
TIMER;
private final TimerInitialization impl = new TimerInitializationImpl();
@Override
public boolean initialize() { return impl.initialize() }
...
(请注意:可能你想保护那个impl类包保护......因为你只需要它一次:
@Test
public testThatEnumCallJustPasses() {
assertThat(MonitorTask.TIMER.initialize(), is(false));
现在你可以:
a)为你的impl课程编写一个共同花园单元测试(不需要任何不健康的权力模拟)
b)如果你想:写另一个简单的"接线"测试...喜欢
TimerInitialization monitorTask = ... inserted via dependency injection OR from MonitorTask.TIMER
monitorTask.initialize()
或类似的东西,以证明你的枚举方法做了"某事"。
是的,这增加了一些样板;但严重的是:你总是想在单例枚举上设置一个界面。你看,直接使用枚举有一个令人讨厌的副作用:它强制你的组件之间相当硬的耦合(至少从测试的角度来看)!
因为迟早,您可能想要测试调用该枚举上的方法的代码;只有当你那时可以做一些像
这样的事情MonitorTask.TIMER.whatever() ...
如果您的所有客户端代码都是直接调用
{{1}}
然后,您的客户端代码无法正常测试。