我想为单例类编写单元测试,但是这个类依赖于ui组件。该类为PageManager
,并具有一些功能可以在页面历史记录中返回并继续。通过单元测试,我喜欢测试这个历史功能,但我不想初始化ui的东西,因为这个测试不需要它。
我是JMockit的新手,我尝试了这个,但没有成功: 这是要嘲笑的原始类:
public final class PageManager {
private static final PageManager INSTANCE = new PageManager();
private final Set<Page> pages = new HashSet<>();
private Page currentPage;
private boolean initialized = false;
private PageManager() {
// Do some UI stuff
}
public static PageManager getInstance() {
return INSTANCE;
}
public void addPage(final Page page) {
pages.add(page);
}
public void initialize() {
// Do some UI stuff
initialized = true;
}
public Page getPage() { return currentPage; }
public void setPage(final Page page) { ... }
public void goBack() { ... };
public void goForward() { ... };
public boolean canGoBack() { ... };
public boolean canGoForward() { ... };
private void activatePage(final Page page) {
// Do some UI stuff
this.currentPage = page;
}
private void deactivatePage(final Page page) {
// Do some UI stuff
}
}
这是模拟版本:
public final class MockedPageManager extends MockUp<PageManager> {
PageManager instance;
@Mock
void $init(final Invocation invocation) {
instance = invocation.getInvokedInstance();
}
@Mock
void initialize() {
// Don't do UI stuff
Deencapsulation.setField(instance, "initialized", true);
}
@Mock
void activatePage(Page page) {
Deencapsulation.setField(instance, "currentPage", page);
page.activate();
}
@Mock
void deactivatePage(Page page) {
}
}
还有一个小测试:
@Test
public void testGoBack() {
new MockedPageManager();
final Page p1 = new Page() { @Override public String getTitle() { return "p1"; } };
final Page p2 = new Page() { @Override public String getTitle() { return "p2"; } };
final PageManager pm = PageManager.getInstance();
pm.addPage(p1);
pm.addPage(p2);
pm.initialize();
pm.setPage(p1)
assertEquals(p1, pm.getCurrentPage());
pm.setPage(p2);
assertEquals(p2, pm.getCurrentPage())
assertTrue(pm.canGoBack());
pm.goBack();
assertEquals(p1, pm.getCurrentPage());
}
在此测试中,JMockit正确调用$init
方法。问题是,在调用NullPointerExceptions
时,测试中会抛出pm.addPage(p1)
。堆栈跟踪说,NPE出现在原始类PageManager
中,因为字段Set pages
是null
。
我的问题是:这个单身人士课程是否被正确嘲笑? $init
方法是否仅覆盖构造函数或Java实例初始化程序,即Set pages = new HashSet&lt;&gt;();
答案 0 :(得分:1)
如上所述here,实例初始化块或语句被复制到每个构造函数中(由编译器)。我怀疑JMockit使用反射/字节代码操作来模拟类的构造函数,有效地规避了所有初始化代码。因此,不执行初始化程序,并且set变量保持为null。如果你真的需要做这个工作,尝试在模拟中正确初始化它。更好的是,重构你的类以允许它在测试中使用(例如,一个额外的包私有构造函数用于测试注入的依赖项;或者将页面历史记录功能移动到它自己的类中。)