当使用Mockito时,我只使用它来模拟依赖关系,即我的工作流程看起来主要是这样的:
我有一个有依赖关系的类:
public class C {
public C (A a, B b) {
this.a = a;
this.b = b;
}
public String fooBar() {
return a.foo() + b.bar();
}
}
在我的测试类中,我模拟出这些依赖关系,并告诉它们在调用某些指定方法时返回哪些值:
public class CSpec {
private A a = mock(A.class);
private B b = mock(B.class);
@Test
public itShouldReturnFooBar() {
when(a.foo()).thenReturn("foo");
when(b.bar()).thenReturn("bar");
C c = new C(a, b);
assertThat(c.fooBar().isEqualTo("foobar"));
}
}
(我希望这个例子不要太简单或太派生;-))。这很好,它允许我在隔离中测试类(这里是C)。尽管如此,我从未使用过Mockito的verify
方法或它的任何其他功能。这样使用Mockito可以/足够吗?
C
是否真的调用了A.foo()和B.bar()方法。所以你可以添加
verify(a).foo();
verify(b).foo();
在批准之前或之后。我认为你不需要也不应该在这里使用它们,但有几种情况下你会需要它们:
- a或b做了一些从c的公共API不可见/不可访问的事情(例如日志记录)
- 你关心的是处决的顺序
- 您需要确保只调用
a.foo
和b.bar
方法,而不是像a.foo2
那样调用其他方法 - 您可以将这些mock用作spy,这样对
a.foo
的调用就会被路由到aReal.foo
verify
方法在Tell Don't Ask编程风格中特别有用。
考虑以下C类版本:
public class C {
public C(A a, B b, CListener L) { ... }
...
public void foobar() {
String result = complexPrivateMethod(a, b);
L.fooBarred(result);
}
}
因此,您不只是计算结果,而是将结果通知一些感兴趣的方(例如用户界面)。
现在要测试foobar,您需要验证侦听器是否被正确调用:
public class CTest {
@Mock CListener mockListener;
...
@Test itShouldTellCAboutFooBar() {
C c = new C(stubbedA, stubbedB, mockedListener);
...
verify(mockedListener).fooBarred("foobar");
}
}
verify
的这种使用对于测试驱动开发是典型的:参见Freeman&Pryce不断发展的以测试为导向的面向对象软件。
因此,如果您想充分利用Mockito的潜力(问题),您最需要在代码中采用相应的设计理念。
是的,这个测试没有问题,非常好。使用存根的简单事实使测试工作,如果您删除或更改存根,那么测试将不工作。
在这种测试中,添加验证语句只会使事情变得多余。
然而,如果你想验证参数、交互的顺序或数量或其他什么,那么你肯定想添加对测试对象和他的合作者之间交互的检查。
这样使用Mockito是完全可以的。但是,如果你的代码变得更加复杂,你需要做更多的事情来让你的代码测试尽可能简单。
另一个小例子:
public void eitherAorB() {
if(somethingIsTrue) {
a.doSomething();
} else {
b.doSomethingElse();
}
}
您可能需要确保在期望的对象上调用了期望的方法。
@Test
public doSomethingShouldBeCalledOnA() {
A a = mock(A.class);
C c = new C(a, new B());
c.setSomeThingIsTrue(true);
eitherAorB();
verify(a).doSomething();
}
@Test
public doSomethingElseShouldBeCalledOnB() {
B b = mock(B.class);
C c = new C(new A(), b);
c.setSomeThingIsTrue(false);
eitherAorB();
verify(b).doSomethingElse();
}
在其他情况下,您可能想知道哪个参数被传递到方法中。为此,您需要一个ArgumentCaptor。
或者在某些情况下,您需要调用实际的方法或使用实际的对象(没有mock),因此是时候监视对象并捕获参数或验证行为了。
所以Mockito还有很多你偶尔需要的东西。
到目前为止给出的答案很好,但还有一些您没有提到的其他功能。@Mock, @Spy, @InjectMocks
注释都非常有用。除了verify(...)
方法之外,还有InOrder类来帮助验证方法调用的顺序。也许您已经使用了matcher方法(<T> any(T t), anyString()
等),但您没有显示您使用了这些工具。