【问题标题】:How does one verify state for a mock object?如何验证模拟对象的状态?
【发布时间】:2016-06-16 00:07:34
【问题描述】:

我有一个在设备上运行的程序 Foo,它首先调用方法 1(),然后调用外部模块 Bar 上的方法 2()。 当 both 被调用时,作为响应,Bar 在 Foo 上调用 request()。 为了模拟 Bar,它有一个对 Foo 的引用和一个调用 foo.request() 的方法 call_Request()

// in class BarTest
@Test
public void barFlow() {
    InOrder inOrder = inOrder(mockBar);
    inOrder.verify(mockBar).method1(anyInt());
    inOrder.verify(mockBar).method2();
    // what to put as 'thenCallMethod'?
    when(mockBar.method2()).thenCallMethod().call_Request();
}
...
// in class Bar
public void call_Request() {
    foo.request();
}

我不能简单地在方法 2 中调用 call_Request(),因为只有当两个方法都按顺序调用时才会发生响应。其他时候,可能会发生不同的反应。

'thenCallMethod' 会做什么 Mockito 技巧?

(我使用的是与 Android Studio 2.1 捆绑的 Mockito 1.10.19 版)

【问题讨论】:

  • 您是否有理由为此需要使用 Mockito? Mockito 可以存根和验证interactions,但是一旦你模拟了一个有状态的协作者,你就必须开始编写聪明而复杂的 InOrder 验证和 Answer 实例(等等)。与mockBar 相比,编写FakeBar 实现类并在测试中检查其状态可能要容易得多。
  • @JeffBowman 实现 Fake 对象需要从 xml 文件中读取的类似规则。我认为使用 Mockito 会更容易。实现所有“胶水”。如果这是最复杂的,它可以得到; method1 后跟 method2,我怎样才能使用 Mock 对象呢?
  • 恕我直言,模拟对象应该能够调用方法。
  • 你知道Answer对象吗?
  • @JeffBowman 但我如何将 Answer 与 InOrder 结合起来?

标签: unit-testing mockito


【解决方案1】:

您似乎没有明确定义您的测试单元是什么。似乎有 3 种可能性:

  1. FooBar 有单独的测试,被测单元是使用Bar 模拟的Foo 实例和使用Foo 模拟的Bar 实例
  2. 被测单元是Foo 的实例,使用Bar 的真实实例,但Bar 实例使用Foo 模拟
  3. 被测单元是Foo 的实例,使用Bar 的真实实例,而Bar 又使用Foo 的现有实例

在情况 1. 您可以测试以下 Bar:

@Test
public void testBar1() {
    Foo mockFoo = Mockito.mock(Foo.class);
    Bar bar = //obtain unit under test that uses mockFoo

    bar.method1(1/*or whatever int value is appropriate*/);
    bar.method2();

    Mockito.verify(mockFoo).request();
}
@Test
public void testBar1() {
    Foo mockFoo = Mockito.mock(Foo.class);
    Bar bar = //obtain unit under test that uses mockFoo

    bar.method2();
    bar.method1(1/*or whatever int value is appropriate*/);

    Mockito.verify(mockFoo, Mockito.never()).request();
}

Foo 的测试看起来像:

Bar mockBar = Mockito.mock(Bar.class);
Foo foo = //obtain unit under test that uses mockBar

// invoke method on foo that would trigger calls to mockBar

InOrder inOrder = inOrder(mockBar);
inOrder.verify(mockBar).method1(anyInt());
inOrder.verify(mockBar).method2();

在案例 2 中,您基本上会从案例 1 中重复对 Foo 的测试。但您只需验证 Foo.request() 是在 Foo 的模拟上调用的 Bar 的实例。 Bar 实例上的调用顺序对于此测试用例没有任何意义。

在第 3 种情况下,您将无法验证任何调用,因为根本没有使用任何模拟。

使用类似的东西

when(mockBar.method2()).thenCallMethod().call_Request();

没有多大意义,因为你给一个 mock 一个实现,它可能在生产代码中没有。

【讨论】:

    猜你喜欢
    • 2010-09-25
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多