接口的Mock测试及Mockito使用

2023-11-07

参考链接

1.Mock测试的目的两个:(1)验证方法调用;(2)指定某个方法的返回值,或者是执行特定的动作

2.所谓的mock就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,以达到两大目的

  1. 验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等

  2. 指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作

3.  (1)UserManager mockUserManager = Mockito.mock(UserManager.class); 需要我们创建了一个mock对象;

    (2)我们必须在调用 loginPresenter.login() 之前,把 mUserManager 引用换成 mockUserManager 所引用的mock对象。最简单的办法,就是加一个setter:

public class LoginPresenter {

    private UserManager mUserManager = new UserManager();

    public void login(String username, String password) {
        if (username == null || username.length() == 0) return;
        if (password == null || password.length() < 6) return;

        mUserManager.performLogin(username, password);
    }

    public void setUserManager(UserManager userManager) {  //<==
        this.mUserManager = userManager;
    }

}

写出来的测试代码如下:

@Test
public void testLogin() throws Exception {
    UserManager mockUserManager = Mockito.mock(UserManager.class);
    LoginPresenter loginPresenter = new LoginPresenter();
    loginPresenter.setUserManager(mockUserManager);  //<==

    loginPresenter.login("xiaochuang", "xiaochuang password");

    Mockito.verify(mockUserManager).performLogin("xiaochuang", "xiaochuang password");
}

4.验证一个对象的某个method得到调用的方法:

   Mockito.verify(mockUserManager).performLogin("xiaochuang", "xiaochuang password");

   Mockito的静态方法 :对于调用次数的验证,除了可以验证固定的多少次,还可以验证最多,最少从来没有等等,方法分别 是: atMost(count),    atLeast(count), never() 等等。


5. 指定mock对象的某些方法的行为:  指定某个方法的返回值,或者是执行特定的动作

(1)

Mockito.verify(mockUserManager).performLogin(Mockito.anyString(), Mockito.anyString());

LoginPresenter 的 login 方法是如下:

public void login(String username, String password) {
    if (username == null || username.length() == 0) return;
    //假设我们对密码强度有一定要求,使用一个专门的validator来验证密码的有效性
    if (mPasswordValidator.verifyPassword(password)) return;  //<==

    mUserManager.performLogin(null, password);
}

这种指定mock对象的某个方法,让它返回特定值的写法如下:

Mockito.when(mockObject.targetMethod(args)).thenReturn(desiredReturnValue);

//先创建一个mock对象
PasswordValidator mockValidator = Mockito.mock(PasswordValidator.class);

//当调用mockValidator的verifyPassword方法,同时传入"xiaochuang_is_handsome"时,返回true
Mockito.when(mockValidator.verifyPassword("xiaochuang_is_handsome")).thenReturn(true);
    
//当调用mockValidator的verifyPassword方法,同时传入"xiaochuang_is_not_handsome"时,返回false
Mockito.when(validator.verifyPassword("xiaochuang_is_not_handsome")).thenReturn(false);
//当调用mockValidator的verifyPassword方法时,返回true,无论参数是什么
Mockito.when(validator.verifyPassword(anyString())).thenReturn(true);

(2)

指定一个方法执行特定的动作,这个功能一般是用在目标的方法是void类型的时候:

LoginPresenter 的 login() 方法:

public void loginCallbackVersion(String username, String password) {
    if (username == null || username.length() == 0) return;
    //假设我们对密码强度有一定要求,使用一个专门的validator来验证密码的有效性
    if (mPasswordValidator.verifyPassword(password)) return;

    //login的结果将通过callback传递回来。
    mUserManager.performLogin(username, password, new NetworkCallback() {  //<==
        @Override
        public void onSuccess(Object data) {
            //update view with data
        }

        @Override
        public void onFailure(int code, String msg) {
            //show error msg
        }
    });
}

我们想让 mUserManager 直接调用传入的 NetworkCallback 的 onSuccess 或 onFailure 方法。这种指定mock对象执行特定的动作的写法如下:

Mockito.doAnswer(desiredAnswer).when(mockObject).targetMethod(args); 传给 doAnswer() 的是一个 Answer 对象,我们想要执行什么样的动作,就在这里面实现

 Mockito.doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        //这里可以获得传给performLogin的参数
        Object[] arguments = invocation.getArguments();

        //callback是第三个参数
        NetworkCallback callback = (NetworkCallback) arguments[2];
        
        callback.onFailure(500, "Server error");
        return 500;
    }
}).when(mockUserManager).performLogin(anyString(), anyString(), any(NetworkCallback.class));
当调用 mockUserManager 的 performLogin 方法时,会执行answer里面的代码,我们上面的例子是直接调用传入的 callback 的 onFailure 方法,同时传给 onFailure 方法500和"Server error"。

自己的实例:采用第5点方法(1):

// 根据客户编号修改客户状态
    @Test
    public void updateCustomerStatusByCustomerNo(){
        String traceLogId = "110";
        String customerNo = "100001";
        CustomerBaseInfoReqDTO reqDTO = new CustomerBaseInfoReqDTO();
        reqDTO.setCustomerNo(customerNo);
        reqDTO.setUpdatedAt(new Date());
        reqDTO.setUpdatedBy("nazi");
        reqDTO.setStatus(CustBaseInfoStatus.CLOSE.getCode());

        Mockito.when(customerBaseInfoBiz.updateCustomerStatusByCustomerNo(Mockito.any(CustomerBaseInfoReqDTO.class))).thenReturn(Boolean.TRUE);
        Result<Boolean> result = customerBaseInfoService.updateCustomerStatusByCustomerNo(reqDTO, traceLogId);
        Assert.assertTrue(result.isSuccess());
        System.out.println("----------------------分隔线--------------------------");
        Mockito.when(customerBaseInfoBiz.updateCustomerStatusByCustomerNo(
                Mockito.any(CustomerBaseInfoReqDTO.class))).thenThrow(BizServerException.class);
        result = customerBaseInfoService.updateCustomerStatusByCustomerNo(reqDTO, traceLogId);
        Assert.assertFalse(result.isSuccess());
        System.out.println("----------------------分隔线--------------------------");
        Mockito.when(customerBaseInfoBiz.updateCustomerStatusByCustomerNo(
                Mockito.any(CustomerBaseInfoReqDTO.class))).thenThrow(NullPointerException.class);
        result = customerBaseInfoService.updateCustomerStatusByCustomerNo(reqDTO, traceLogId);
        Assert.assertFalse(result.isSuccess());
    }
 // 根据客户号查询客户账户信息
    @Test
    public void findCustAcctByCustomerNo(){
        List<CustomerAccountQueryResDTO> resDTOList = new ArrayList<>();
        Mockito.when(customerAccountManager.queryByCustomerNo(Mockito.any())).thenReturn(resDTOList);
        String customerNo = "0000000000020005";
        Result<List<CustomerAccountQueryResDTO>> result = customerInfoQueryService.findCustAcctByCustomerNo(customerNo,"110");
        Assert.assertTrue(result.isSuccess());
    }

Spy

目的:除非指定,否者调用这个对象的默认实现,同时又能拥有验证方法调用的功能

相异点:

spy与mock的唯一区别就是默认行为不一样:spy对象的方法默认调用真实的逻辑,mock对象的方法默认什么都不做,或直接返回默认值
//假设目标类的实现是这样的
public class PasswordValidator {
    public boolean verifyPassword(String password) {
        return "xiaochuang_is_handsome".equals(password);
    }
}

@Test
public void testSpy() {
    //跟创建mock类似,只不过调用的是spy方法,而不是mock方法。spy的用法
    PasswordValidator spyValidator = Mockito.spy(PasswordValidator.class);

    //在默认情况下,spy对象会调用这个类的真实逻辑,并返回相应的返回值,这可以对照上面的真实逻辑
    spyValidator.verifyPassword("xiaochuang_is_handsome"); //true
    spyValidator.verifyPassword("xiaochuang_is_not_handsome"); //false
    
    //spy对象的方法也可以指定特定的行为
    Mockito.when(spyValidator.verifyPassword(anyString())).thenReturn(true);
    
    //同样的,可以验证spy对象的方法调用情况
    spyValidator.verifyPassword("xiaochuang_is_handsome");
    Mockito.verify(spyValidator).verifyPassword("xiaochuang_is_handsome"); //pass
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

接口的Mock测试及Mockito使用 的相关文章

随机推荐

  • 移动端日历插件(vue3-small-calendar)

    背景 同事做移动端项目时希望用到可平铺选择的日历插件 然度娘无过最后问题到我这边 虽然咱不是前端但是秉着技术问题不是问题且问题到我为止的原则 自己研究了2天完成了vue3 small calendar插件 此插件目前已发布npm 大家觉得可
  • 如何评价一个规划方案的合理性?记xx项目规划单位招标

    今天共4家公司设计单位参与投标 上午两家 下午两家 公司请了两位专家来评价各家方案 从整体规划方案水平上看 投标方案水平都不是特别突出 没有让人眼前一亮的方案 有的只是一些小创意小想法 对于新的规划理念 新的规划思维没有看到 另外大家对于西
  • 安装 inotify-tools

    摘要 inotify tools 是一款google出的用于监控文件系统的软件 一 软件下载地址官方站点地址 http inotify tools sourceforge net 仓库地址 https github com rvoicila
  • 华为OD机试真题(Java),整数编码(100%通过+复盘思路)

    一 题目描述 实现一个整数编码方法 使得待编码的数字越小 编码后所占用的字节数越小 编码规则如下 编码时7位一组 每个字节的低7位用于存储待编码数字的补码 字节的最高位表示后续是否还有字节 置1表示后面还有更多的字节 置0表示当前字节为最后
  • .sh脚本bash命令 从输出中过滤字符串(正则)替换json中value值 grep命令 sed命令 替换字符串

    bash命令 获取 sh文件当前目录 输出值赋给变量 grep命令查询文件 变量方法 sed命令正则替换文件或变量中字符串 带颜色输出 获取 sh文件当前目录 获取 sh文件当前目录 basepath cddirname 0 pwd bas
  • vue2实例

    目录 数据与方法 你提到vue有两种数据和方法 js是不是只有一种 vue2自带的实例和方法 vue2 会和jQuery冲突d的问题 vue2中被人吐槽的this vue3已改进 箭头函数和普通函数中的this 生命周期 数据与方法 没看懂
  • 深入分析 ESP32 的 WiFi 状态机

    本工程已托管到 GitHub 具体路径是 https github com tidyjiang8 esp32 projects tree master sta 在前一篇博客 让 ESP32 连接到你的 WiFi 热点 中 我们已经简单地分析
  • jquery+ajax清除session,并跳出iframe框架页面

    集合页面
  • Checkstyle检查规则

    Checkstyle是一个检查java文件编码规范的开源工具 最新版本支持184个检查规则 Checkstyle官网如下 https checkstyle sourceforge io Checkstyle的GitHub地址如下 https
  • 企业的述职如何做才有效?

    360度考核法又称全方位考核法 是指通过被考核者自己 同事 上级 下属以及客户对考核者进行全方位评价 以帮助其提高能力或业绩 职如何做才有效 每年的元旦前后很多单位都会针对全员做一件事情 述职 述职这个词在古时候诸侯向天子陈述职守 现在指基
  • 8.4-中断系统小结(cpu中断七个问题)

    README 本文转自bilibili 计算机组成原理 哈工大刘宏伟 的视频讲解 非常棒 墙裂推荐 1 中断介绍 1 作用 用中断系统实现了外设数据的输入输出 还可以用于程序调试 计算机系统的异常事件 都可以用中断系统来处理 2 中断因素
  • docker创建kafka(带SASL认证)

    1 准备文件kafka server jaas conf KafkaServer org apache kafka common security plain PlainLoginModule required username admin
  • c++中map的3中遍历方式

    一 说明 容器都有成员begin和end 其中begin成员复制返回指向第一个元素的迭代器 而end成员返回指向容器尾元素的下一个位置的迭代器 它是一个不存在的元素位置 1 map
  • proteus8.9闪退解决办法(亲测有效)

    ptoteus8 9闪退解决办法 win10安装proteus8 9以后经常出现闪退的情况 网上搜到的大部分都在说是安装路径的原因 但是我这里两台电脑 一台修改了安装路径解决了闪退 另一台却并没有生效 不管怎么设置安装路径 总有闪退的情况
  • 应用层HTTP数据包的截获与还原技术的实现

    摘要 在因特网日益发展壮大的今天 万维网在其上的通信量已经超过90 万维网信息的安全问题已经越来越被人们所重视 而作为万维网应用层核心协议的http协议是基础 当网络发生异常时 对网络上传输的数据进行监视和分析 是网管人员解决网络故障的一种
  • 全同态加密算法深入解析

    陈智罡老师全同态加密算法深入解析 https www 8btc com article 392931
  • 联软科技安全准入门户平台RCE(命令执行)漏洞

    联软科技安全准入门户平台RCE 命令执行漏洞 前言 声明 一 漏洞描述 二 影响平台 三 漏洞复现 四 修复方案 五 工具链接 前言 联软科技安全准入门户平台 commondRetStr处存在远程代码执行漏洞 攻击者可以获取服务器权限 声明
  • AIGC - 文本生成视频大模型-英文-通用领域 (Text-to-video-synthesis Model in Open Domain)

    文本生成视频大模型 英文 通用领域 Text to video synthesis Model in Open Domain 本模型基于多阶段文本到视频生成扩散模型 输入描述文本 返回符合文本描述的视频 仅支持英文输入 This model
  • WebRTC在浏览器中的演示

    WebRTC在chrome浏览器里演示的例子很多 WebRTC的源码里就有 但是在Firefox浏览器里 例子不能使用 网上的资料说要把 media peerconnection enabled 设置为True 但是Firefox浏览器里
  • 接口的Mock测试及Mockito使用

    参考链接 1 Mock测试的目的两个 1 验证方法调用 2 指定某个方法的返回值 或者是执行特定的动作 2 所谓的mock就是创建一个类的虚假的对象 在测试环境中 用来替换掉真实的对象 以达到两大目的 验证这个对象的某些方法的调用情况 调用