Mockito - 感觉我没有充分发挥其潜力



当使用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可以/足够吗?

Verify通常用于检查C是否真的调用了A.foo()和B.bar()方法。所以你可以添加
verify(a).foo();
verify(b).foo();

在批准之前或之后。我认为你不需要也不应该在这里使用它们,但有几种情况下你会需要它们:

  • a或b做了一些从c的公共API不可见/不可访问的事情(例如日志记录)
  • 你关心的是处决的顺序
  • 您需要确保只调用a.foob.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()等),但您没有显示您使用了这些工具。

相关内容

  • 没有找到相关文章

最新更新