如何使用 Mockito 的 verify() 方法验证一个方法被调用了两次

431

我想通过Mockito的verify方法来验证一个方法是否至少被调用了一次。我使用了verify,但它报错了:

org.mockito.exceptions.verification.TooManyActualInvocations: 
Wanted 1 time:
But was 2 times. Undesired invocation:
2个回答

717

使用适当的VerificationMode:

import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

verify(mockObject, atLeast(2)).someMethod("was called at least twice");
verify(mockObject, times(3)).someMethod("was called exactly three times");

25
你可以使用Mockito.times(...)代替VerificationModeFactory.times(...)进行静态导入。 - Wim Deblauwe
28
通常不建议导入包含 "internal" 的包(import static org.mockito.internal.verification.VerificationModeFactory.times;),而应该使用 import static org.mockito.Mockito.times;。请注意,这并不会改变原始代码的含义。 - Roger
有没有其他的方式来写 times(1)? - Glenn Bech
5
你可以忽略这个链接,它是隐含的;默认的verify(mockObject).someMethod("")检查恰好有一次交互(不多不少)。如果你想要至少一个方法调用,可以使用atLeastOnce()限定符。 - nbrooks
1
@Roger 我同意你的观点,对于像我这样的TDD初学者来说,静态导入会让我更加困惑,不知道该记住哪些方法或使用哪个框架(Mockito、Espresso还是普通的单元测试)。 - Phong Nguyen

8

Kotlin:

构建 gradle:

testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"

代码:

interface MyCallback {
  fun someMethod(value: String)
}

class MyTestableManager(private val callback: MyCallback){
  fun perform(){
    callback.someMethod("first")
    callback.someMethod("second")
    callback.someMethod("third")
  }
}

测试:

import com.nhaarman.mockitokotlin2.times
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.mock
...
val callback: MyCallback = mock()
val uut = MyTestableManager(callback)
uut.perform()

val captor: KArgumentCaptor<String> = com.nhaarman.mockitokotlin2.argumentCaptor<String>()

verify(callback, times(3)).someMethod(captor.capture())

assertTrue(captor.allValues[0] == "first")
assertTrue(captor.allValues[1] == "second")
assertTrue(captor.allValues[2] == "third")

针对Java:

Lombok可用于简化代码。如果您喜欢的话,您也可以手动编写构造函数。

build.gradle文件:

testImplementation "org.mockito:mockito-core:3.6.28"

代码:

// MyCallback.java
public interface MyCallback {
  void someMethod(String value);
}
// MyTestableManager.java
public class MyTestableManager {
  private MyCallback callback;

  public MyTestableManager(MyCallback callback) {
    this.callback = callback;
  }

  public void perform(){
    callback.someMethod("first");
    callback.someMethod("second");
    callback.someMethod("third");
  }
}

测试:

import org.mockito.Mockito.times;
import org.mockito.Mockito.verify;
import org.mockito.Mock;
import org.mockito.Captor;
// whatever other imports you need
@Mock
private MyCallback callback;
@Captor
private ArgumentCaptor<String> captor;

private MyTestableManager uut = new MyTestableManager(callback);

// in your test method:
uut.perform()

verify(callback, times(3)).someMethod(captor.capture())

assertTrue(captor.getAllValues().get(0) == "first")
assertTrue(captor.getAllValues().get(1) == "second")
assertTrue(captor.getAllValues().get(2) == "third")

如果你对我的编辑有疑问:在Java中,基于注解的模拟创建通常更可取,但我不确定在Mockito Kotlin中是否也是这样。至于将manager重命名为uut,那只是惯例 - 被测试的对象(被测试的单元)通常被命名为uut或sut(不确定后者代表什么)。 - Egor Hans
感谢您对“captor”机制进行详细阐述,效果非常好! - Jonathan F.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接