gpt4 book ai didi

java - 为单元测试模拟单例

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:07:50 27 4
gpt4 key购买 nike

我想为单例类编写单元测试,但此类对 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());
}

在这个测试中,$init 方法被 JMockit 正确调用。问题是,当调用 pm.addPage(p1) 时,测试中会抛出 NullPointerExceptions。堆栈跟踪表明,NPE 发生在原始类 PageManager 中,因为字段 Set pagesnull

我的问题是:是否正确模拟了这个单例类? $init 方法是否仅覆盖构造函数或 Java 实例初始化程序,即 Set pages = new HashSet<>();

最佳答案

如前所述here ,实例初始化 block 或语句被复制到每个构造函数(由编译器)。我怀疑 JMockit 使用反射/字节码操作来模拟类的构造函数,从而有效地规避了所有初始化代码。因此初始化器不会被执行并且设置的变量保持为空。如果你真的必须让它工作,请尝试在模拟中正确初始化它。更好的是,重构您的类以允许其在测试中使用(例如,用于使用注入(inject)的依赖项进行测试的附加包私有(private)构造函数;或将页面历史记录功能移至其自己的类)。

关于java - 为单元测试模拟单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18869692/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com