【发布时间】:2017-09-06 16:24:12
【问题描述】:
假设我有一个简单依赖的类:
public interface Dependency {
int doSomething(int value);
void doMore(int value);
int doALotMore(int value);
}
public final class A implements SomeInterface {
private final Dependency dep;
public A (Dependency dep) {
this.dep = dep;
}
@Override
public int add(final int x) {
dep.doMore(x);
return x + dep.doSomething(x) + dep.doALotMore(x);
}
}
我正在使用模拟编写测试:
public class TestA {
private Dependency mockDep;
private SomeInterface a;
@Before
public void setUp() {
mockDep = Mockito.mock(Dependency.class);
a = new A(mockDep);
}
@Test
public void shouldAdd() {
final int x = 5;
when(mockDep.doSomething(x)).thenReturn(6);
when(mockDep.doALotMore(x)).thenReturn(7);
int actual = a.add(x);
assertThat(actual, is(18));
verify(mockDep, times(1)).doSomething();
verify(mockDep, times(1)).doALotMore();
verify(mockDep, times(1)).doMore();
verifyNoMoreInteractions(mockDep);
}
}
到目前为止一切顺利。
所以问题是:我们是否通过验证依赖项的使用方式违反了A 类的封装?是否真的需要测试以这种方式使用的依赖项?我们不应该像黑盒一样测试A(从测试用例中删除verify 调用,只留下assertThat)吗?在这种情况下如何处理依赖关系?
我问的原因是我发现自己编写了大量的验证依赖代码,似乎我们开始测试有关类的实际内部实现细节。我对此感到不舒服,因为当我尝试以另一种方式重写此实现细节时,我需要重写测试用例,尽管例如add 的结果将是相同的。如果我将我的类作为黑盒进行测试,我可以更改实现细节并仍然确保给定的输入会给出相同的输出。
或者有必要对实现细节进行实际测试,这就是单元测试本身的意义所在?这对我来说似乎有些不对劲。
请考虑这个测试:
public class TestA {
private Dependency mockDep;
private SomeInterface a;
private final int x = 5;
@Before
public void setUp() {
mockDep = Mockito.mock(Dependency.class);
a = new A(mockDep);
when(mockDep.doSomething(x)).thenReturn(6);
when(mockDep.doALotMore(x)).thenReturn(7);
}
@Test
public void shouldAdd() {
int actual = a.add(x);
assertThat(actual, is(18));
}
}
【问题讨论】:
-
如果
A#add(int)被定义为将特定方法调用的结果添加到x本身的方法,则可以测试它是否实际调用了该方法并将其添加到 @987654332 @。 When 和 whereadd调用依赖类的方法实际上对您的测试无关紧要,并且您无论如何都不会测试它(在您的示例中)。因此,该测试对我来说看起来不错。你有一个你觉得不舒服的测试用例的例子吗? (verifyNoMoreInteractions(mockDep);的用法可以有争议,但这取决于测试对象)。 -
单元测试是灰盒/白盒测试。它不应该被用作黑盒测试。它的目的是测试测试中类的所有逻辑,包括它如何与其依赖项交互。模拟有助于避免测试任何依赖代码。
-
根据经验,您希望验证交互或存根呼叫。如果你发现自己两者都做,这通常是一个不好的迹象。例如,在这种情况下,您希望存根行为。如果您的模拟没有被调用,那么答案将是错误的,不需要确保您的存根已被调用。如果您想确保没有发生其他交互,我建议启用严格模式 (static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/…)。
标签: java unit-testing testing mocking encapsulation