【发布时间】:2011-02-28 22:21:18
【问题描述】:
我需要为以下方法(简化)编写一个 JUnit 测试:
/** Return name of previous entry or name of given entry if no previous entry. */
public String getPreviousName(TreeEntry entry) {
if (entry.getPrevious() != null) {
return entry.getPrevious().getName();
} else {
return entry.getName();
}
}
我只是不知道我应该如何测试这个。我也可以
a) 使用 Mocks 模拟出参数及其之前的条目或
b) 创建一个真正的 TreeEntry,它是真正的先前条目
使用模拟的问题是,我需要在测试用例中说明实际实现需要使用哪种方法,例如这里我说正确的名称是通过 TreeEntry 的 getPrevious() 获得,然后通过前一个条目的 getName() 获得(不考虑 if null 的情况,因为这基本上不是问题):
TreeEntry mockEntry = mock(TreeEntry.class);
TreeEntry mockPreviousEntry = mock(TreeEntry.class);
when(mockEntry.getPrevious()).thenReturn(mockPreviousEntry);
when(mockPreviousEntry.getName()).thenReturn("testName");
assertEquals("testName", classUnderTest.getPreviousName(mockEntry));
但实施者也可以像这样实施它:
return NameService.getName(entry.getPrevious());
只是测试没关系。
但是,如果我使用没有模拟的经典单元测试,我就会遇到另一个问题。 TreeEntry 的构造函数非常复杂。它有 5 个需要有效对象的参数。所以创建类似这样的东西非常复杂:
TreeEntry entry = new TreeEntry(...);
TreeEntry previousEntry = new TreeEntry(...);
entry.setPrevious(previousEntry);
previousEntry.setName("testName");
assertEquals("testName", classUnderTest.getPreviousName(entry));
代码会比这长得多,因为构造函数需要复杂的参数。另一件事是构造函数访问文件系统以从那里加载它的内容,因此它增加了单元测试的速度。
使用经典方法,它还将测试更多地与 TreeEntry 的实现联系在一起。因为如果在 TreeEntry 中使用构造函数或前一个条目的设置进行了更改,则也需要在测试中进行更改。如果忘记了,即使测试的类不是 TreeEntry,也会导致测试失败。
你认为单元测试的正确方法是什么?
我个人更喜欢嘲笑的方式。是否可以说在测试用例中我已经指定了哪些是被测类的协作者,因为这在某种程度上也更多地属于设计而不是实现?
最好的问候, 亚历克斯
【问题讨论】:
标签: java unit-testing mocking