Java测试框架系列:Mockito 详解:第三部分:结果验证

本文详细介绍了Mockito测试框架中的结果验证,包括方法调用的次数验证,如允许至少或最多调用几次的方法,验证方法是否只调用一次,以及验证调用的确切次数。此外,还讲解了方法执行时间的验证,如何在给定的毫秒数后触发验证,适用于测试异步代码。最后,文章讨论了方法调用顺序验证,如何按顺序验证mock对象的交互,并提供了相关示例。
部署运行你感兴趣的模型镜像

Mockito 详解:第三部分:结果验证

零:准备代码

public class Foo {

    private Bar bar;
    private Tou tou;

    public int sum(int a, int b) {
        return bar.add(a, b);
    }

    public int count() {
        bar.badCode();
        return 5;
    }
}
public class Bar {

    public int add(int a, int b) {
        return a + b;
    }

    public void badCode() {
        throw new RuntimeException("bad bar code");
    }
}
public class Tou {

    public void tou() {
        throw new RuntimeException("tou");
    }
}

一:方法是否被调用/方法的调用的次数

  • atLeast(int minNumberOfInvocations)允许至少 x 次调用的验证。
  • atLeastOnce()允许至少一次调用的验证。
  • atMost(int maxNumberOfInvocations)允许最多 x 次调用的验证。
  • atMostOnce()允许最多一次调用的验证。
  • never() times(0)的别名,见times(int) 。
  • only()允许检查给定的方法是否只调用一次。
  • times(int wantedNumberOfInvocations)允许验证调用的确切次数。
  • verify(T mock)验证某些行为发生过一次
  • verify(T mock, VerificationMode mode)验证某些行为至少发生过一次/确切的次数/从未发生过。
  • verifyNoInteractions(Object... mocks)验证给定的mock对象上没有发生交互。
  • verifyNoMoreInteractions(Object... mocks)检查任何给定的mock对象上是否有任何未经验证的交互。
  • validateMockitoUsage()验证测试代码中是否有书写错误的地方。

示例:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {

    //foo 对象内部的成员变量会自动被 @Mock 注解的生成的对象注入。
    @InjectMocks
    private Foo foo;

    //bar 对象会自动的注入到 @InjectMocks 注解的对象的成员变量中去。
    @Mock(lenient = true)
    private Bar bar;

    //tou 对象会自动的注入到 @InjectMocks 注解的对象的成员变量中去。
    @Mock(lenient = true)
    private Tou tou;

    @Test
    public void doReturnTest() {
        Mockito.doReturn(7).when(bar).add(1, 2);

        foo.sum(1, 2);

        //1:验证 bar.add(1,2) 方法被调用了一次。
        Mockito.verify(bar).add(1, 2);
        //2:等同于1。
        Mockito.verify(bar, Mockito.times(1)).add(1, 2);
        //3:验证 bar.add(1,2) 方法至少被调用了n次。
        Mockito.verify(bar, Mockito.atLeast(1)).add(1, 2);
        //4:验证 bar.add(1,2) 方法至少被调用了一次。
        Mockito.verify(bar, Mockito.atLeastOnce()).add(1, 2);
        //5:验证 bar.add(1,2) 方法至多被调用了n次。
        Mockito.verify(bar, Mockito.atMost(1)).add(1, 2);
        //6:验证 bar.add(1,2) 方法至多被调用了一次。
        Mockito.verify(bar, Mockito.atMostOnce()).add(1, 2);
        //7:验证 bar.badCode() 方法从没有被调用过。
        Mockito.verify(bar, Mockito.never()).badCode();
        //8:验证 bar.add(1,2) 方法只被调用了一次。
        Mockito.verify(bar, Mockito.only()).add(1, 2);
        //9:验证给定的mock对象上没有发生交互。
        Mockito.verifyNoInteractions(tou);
        //10:检查任何给定的mock对象上是否有任何未经验证的交互。(测试执行过程中和bar对象的交互都验证过了,此时验证通过)
        Mockito.verifyNoMoreInteractions(bar);
        //11:验证测试代码中是否有书写错误的地方。
        Mockito.validateMockitoUsage();
    }

}

二:方法执行时间的验证

  • after(long millis)在给定的毫秒数后将触发验证,允许测试异步代码。
  • timeout(long millis)验证将一遍又一遍地触发,直到给定的毫秒数,允许测试异步代码。
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {

    //foo 对象内部的成员变量会自动被 @Mock 注解的生成的对象注入。
    @InjectMocks
    private Foo foo;

    //bar 对象会自动的注入到 @InjectMocks 注解的对象的成员变量中去。
    @Mock(lenient = true)
    private Bar bar;

    //tou 对象会自动的注入到 @InjectMocks 注解的对象的成员变量中去。
    @Mock(lenient = true)
    private Tou tou;

    @Test
    public void doReturnTest() {
        Mockito.doReturn(7).when(bar).add(1, 2);

        foo.sum(1, 2);

        //1:验证 bar.add(1,2) 方法在100ms内执行完成。在给定的毫秒数后将触发验证,允许测试异步代码。
        Mockito.verify(bar, Mockito.after(100)).add(1, 2);
        //2:验证 bar.add(1,2) 方法在100ms内执行完成。验证将一遍又一遍地触发,直到给定的毫秒数,允许测试异步代码。
        Mockito.verify(bar, Mockito.timeout(100)).add(1, 2);
    }

}

更多关于timeout()方法的介绍

验证将一遍又一遍地触发,直到给定的毫秒数,允许测试异步代码。当与mock对象的交互尚未发生时很有用。timeout()方法的广泛使用可能是一种代码异味——有更好的方法来测试并发代码。

timeout()after之间的差异在 after(long) 的 Javadoc.

   //当 somemethod()的执行时间不大于100毫秒时通过
   //满足验证时立即退出(例如,可能不会等待100毫秒)
   verify(mock, timeout(100)).someMethod();
   //上面代码也可以写成这样:
   verify(mock, timeout(100).times(1)).someMethod();

   //只要 someMethod() 在两次调用内时间小于100 ms则通过
   verify(mock, timeout(100).times(2)).someMethod();

   //等效于上方的代码:
   verify(mock, timeout(100).atLeast(2)).someMethod();
 

更多关于after(long)方法的介绍

在给定的毫秒数后将触发验证,允许测试异步代码。当与mock对象的交互尚未发生时很有用。after()方法的广泛使用可能是一种代码异味——有更好的方法来测试并发代码。

尚未实现与 InOrder 验证一起使用。timeout()和之间的差异after()解释如下。

   //100毫秒后,somemethod()执行完毕则验证通过
   verify(mock, after(100)).someMethod();
   //上面代码也可以写成这样:
   verify(mock, after(100).times(1)).someMethod();

   //100毫秒后,somemethod()执行2次完毕则验证通过
   verify(mock, after(100).times(2)).someMethod();

   //100毫秒后,如果 someMethod() 没有执行则验证通过
   verify(mock, after(100).never()).someMethod();

   //使用给定的验证模式验证在100ms内someMethod()方法的执行,
   //在使用你自定义的验证模式时是有用的。
   verify(mock, new After(100, yourOwnVerificationMode)).someMethod();
 

timeout() 与 after()

  • timeout() 验证通过后立即退出并成功
  • after() 等待完整的时间来检查验证是否通过

例子:

   //1.
   mock.foo();
   verify(mock, after(1000)).foo();
   //等待 1000 ms之后验证会成功

   //2.
   mock.foo();
   verify(mock, timeout(1000)).foo();
   //立即成功

三:方法调用顺序验证

  • inOrder(Object... mocks)创建InOrder对象,以允许按顺序验证mock的对象。
  • calls(int wantedNumberOfInvocations)允许按顺序进行非贪婪调用的验证。

关于inOrder

创建InOrder对象以允许按顺序验证模拟的对象。

   InOrder inOrder = inOrder(firstMock, secondMock);

   inOrder.verify(firstMock).add("was called first");
   inOrder.verify(secondMock).add("was called second");
 

按顺序验证是灵活的 -您不必一一验证所有交互,而只需按顺序验证您感兴趣的那些交互

此外,您可以创建 InOrder 对象,仅传递与有序验证相关的mock对象。

InOrder验证是“贪婪的”,但您几乎不会注意到它。

如果您想了解更多信息可以加我qq3177181324

从 Mockito 1.8.4 开始,您可以以顺序敏感的方式使用verifyNoMoreInteractions()。

关于calls()

允许按顺序进行非贪婪验证。例如

   inOrder.verify( mock, calls( 2 )).someMethod( "some arg" );
  • 如果该方法被调用 3 次,则不会失败,与 times(2) 不同
  • 与 atLeast(2) 不同,不会将第三次调用标记为已验证

这种验证方式只能用于顺序验证。

四:验证方法参考

修饰符和类型方法和说明
static VerificationAfterDelayafter(long millis)在给定的毫秒数后将触发验证,允许测试异步代码。
static VerificationModeatLeast(int minNumberOfInvocations)允许至少 x 调用的验证。
static VerificationModeatLeastOnce()允许至少一次调用的验证。
static VerificationModeatMost(int maxNumberOfInvocations)允许最多 x 次调用的验证。
static VerificationModeatMostOnce()允许最多一次调用的验证。
static VerificationModecalls(int wantedNumberOfInvocations)允许按顺序进行非贪婪调用的验证。
static Object[]ignoreStubs(Object... mocks)为了验证,忽略给定mock的存根方法。
static InOrderinOrder(Object... mocks)创建InOrder对象,允许按顺序验证mock的对象。
static LenientStubberlenient()宽松存根,绕过“严格存根”验证(请参阅参考资料Strictness.STRICT_STUBS)。
static VerificationModenever() times(0)的别名,见times(int)
static VerificationModeonly()允许检查给定的方法是否只调用一次。
static voidreset(T... mocks)聪明 Mockito 用户几乎不使用此功能,因为他们知道这可能是测试不佳的迹象。
static VerificationWithTimeouttimeout(long millis)验证将一遍又一遍地触发,直到给定的毫秒数,允许测试异步代码。
static VerificationModetimes(int wantedNumberOfInvocations)允许验证调用的确切次数。
static voidvalidateMockitoUsage()首先,如果有任何问题,我鼓励您阅读 Mockito FAQ: github.com/mockito/moc…
static Tverify(T mock)验证某些行为发生过一次
static Tverify(T mock, VerificationMode mode)验证某些行为至少发生过一次/确切的次数/从未发生过。
static voidverifyNoInteractions(Object... mocks)验证给定的模拟上没有发生交互。
static voidverifyNoMoreInteractions(Object... mocks)检查任何给定的模拟是否有任何未经验证的交互。

最后小编在学习过程中整理了一些学习资料,可以分享给做软件测试工程师的朋友们,相互交流学习,需要的可以加入我的学习交流群 323432957 或加微dingyu-002即可免费获取Python自动化测开及Java自动化测开学习资料(里面有功能测试、性能测试、python自动化、java自动化、测试开发、接口测试、APP测试等多个知识点的架构资料)

您可能感兴趣的与本文相关的镜像

Anything-LLM

Anything-LLM

AI应用

AnythingLLM是一个全栈应用程序,可以使用商用或开源的LLM/嵌入器/语义向量数据库模型,帮助用户在本地或云端搭建个性化的聊天机器人系统,且无需复杂设置

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值