文档章节

对代码更有信心--单元测试工具Mockito简单介绍

zgw06629
 zgw06629
发布于 2015/04/27 12:03
字数 1064
阅读 445
收藏 7

许多同事怕写单元测试的一个主要原因(或借口)就是依赖太多(redis,mysql,webservice等)。但其实可以用Mockito来模拟相关行为,不用费力去准备各种依赖环境,这时只需专注于业务逻辑即可。

比如有这么一个业务需求,若用户已经购买了容量(20GB,200GB),直接返回容量,若未购买,再判断该用户是否存在,若不存在,提示该用户不存在;若存在则判断是否为激活用户,若为激活用户返回2GB, 若为非激活用户返回1GB。

controller代码如下:

@Autowired
private StorageService storageService;
@Autowired
private UserService userService;
@RequestMapping({ "/storage/userId/{userId}" })
@ResponseBody
public CommonResultDTO getUserStorage(@PathVariable("userId") String userId){
    CommonResultDTO result = new CommonResultDTO();
    Integer capacity = storageService.getUserStorage(userId); //查询用户是否购买了容量
     
    if(capacity==null){ //没有购买
        User user = userService.getUser(userId); //查询该用户
        if(user==null){ //用户不存在
            result.setStatus(FAILURE_STATUS);
            result.setMessage(USER_NOT_EXIST);
        }
        else if(user.getStatus()==ACTIVE) //激活用户 默认返回2GB
            capacity = DEFAULT_ACTIVE_USER_CAPACITY;
        else if(user.getStatus() == INACTIVE) //未激活用户 默认返回1GB
            capacity = DEFAULT_INACTIVE_USER_CAPACITY;
    }
    result.setData(capacity);
    return result;
}

假如只想测试上述业务逻辑,而不想费力去开启本地数据库,并准备各种数据,如插入一条用户购买记录(insert user_storage (user_id, product_id) values(1, 1)),插入一个激活用户(insert into user(user_id, status) values(1, 0)),一个非激活用户。若上述业务还用到了缓存,那准备的工作就更多了.。估计此时大部分开发人员已经打消了写单元测试的念头了,并祈祷这段代码能平平安安。

于是轻易地就把命运交给老天了。

幸好有了Mockito框架,命运又可以掌握在自己手中了,它提供了易用的Api可以让我们仅需关注主要业务逻辑而无需耗费精力在准备繁琐的测试环境上。

见如下示例代码:

@RunWith(MockitoJUnitRunner.class)
public class StorageControllerTest {
    @InjectMocks
    private StorageController controller;
    @Mock
    private UserService userService;
    @Mock
    private StorageService storageService;
    @Test
    public void test_user_not_exist(){
        //1. 验证用户不存在
        String userId = "notexist";
        // 当执行storageService.getUserStorage(userId)时直接返回空 表示未购买
        Mockito.when(storageService.getUserStorage(userId)).thenReturn(null);
        // 当执行userService.getUser(userId)时 返回空 表示用户不存在
        Mockito.when(userService.getUser(userId)).thenReturn(null);
         
        CommonResultDTO result = controller.getUserStorage(userId);
        Assertions.assertThat(result.getStatus()).isEqualTo(FAILURE_STATUS);
        Assertions.assertThat(result.getMessage()).isEqualTo(USER_NOT_EXIST);
        //验证是否执行了storageService.getUserStorage(userId)一次;
        Mockito.verify(storageService).getUserStorage(userId);
        //验证是否执行了userService.getUser(userId)一次;
        Mockito.verify(userService).getUser(userId);
    }
    @Test
    public void test_inactive_and_not_buy_user_storage(){
        //2. 验证未购买且未激活用户的返回容量
        // 定义一未激活状态用户
        String userId = "1";
        User user = new User();
        user.setStatus(INACTIVE);
        // 当执行storageService.getUserStorage(userId)时直接返回空 表示未购买
        Mockito.when(storageService.getUserStorage(userId)).thenReturn(null);
        // 当执行userService.getUser(userId)时 返回上面定义的未激活状态User
        Mockito.when(userService.getUser(userId)).thenReturn(user);
         
        CommonResultDTO result = controller.getUserStorage(userId);
        Assertions.assertThat(result.getData()).isEqualTo(DEFAULT_INACTIVE_USER_CAPACITY);
        //验证是否执行了storageService.getUserStorage(userId);
        Mockito.verify(storageService).getUserStorage(userId);
        //验证是否执行了userService.getUser(userId);
        Mockito.verify(userService).getUser(userId);
    }
    @Test
    public void test_active_and_not_buy_user_storage(){
        //3. 验证未购买但激活用户的返回容量
        // 定义一激活状态用户对象
        String userId = "1";
        User user = new User();
        user.setStatus(ACTIVE);
        // 当执行storageService.getUserStorage(userId)时直接返回空 表示未购买
        Mockito.when(storageService.getUserStorage(userId)).thenReturn(null);
        // 当执行userService.getUser(userId)时 返回上面定义的激活状态User
        Mockito.when(userService.getUser(userId)).thenReturn(user);
         
        CommonResultDTO result = controller.getUserStorage(userId);
        Assertions.assertThat(result.getData()).isEqualTo(DEFAULT_ACTIVE_USER_CAPACITY);
        //验证是否执行了storageService.getUserStorage(userId);
        Mockito.verify(storageService).getUserStorage(userId);
        //验证是否执行了userService.getUser(userId);
        Mockito.verify(userService).getUser(userId);
    }
    @Test
    public void test_had_bought_user_storage(){
        //4. 验证已购买用户的返回容量
        String userId = "1";
        // 当执行storageService.getUserStorage(userId)时直接返回20 表示用户购买了20GB的容量
        final int CAPACITY_20 = 20;
        Mockito.when(storageService.getUserStorage(userId)).thenReturn(CAPACITY_20);
         
        CommonResultDTO result = controller.getUserStorage(userId);
        Assertions.assertThat(result.getData()).isEqualTo(CAPACITY_20);
        //验证是否执行了storageService.getUserStorage(userId);
        Mockito.verify(storageService).getUserStorage(userId);
        //用户已购买的情况下 不会执行userService.getUser(userId) 故此处设置times(0) 表示未执行
        Mockito.verify(userService,Mockito.times(0)).getUser(userId);
    }
}

无需依赖外部环境,只须通过Mockito.when().thenReturn()来准备各种待测条件下的数据(如用户不存在、激活用户、非激活用户等)。

我想若通过了上面这个逻辑严密的测试,对这段代码应该是格外有信心了吧。不用每天在胸前画十字了。

见测试结果:

补充:

Mockito maven 坐标

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.9.5</version>
</dependency>


© 著作权归作者所有

共有 人打赏支持
zgw06629
粉丝 16
博文 54
码字总数 30471
作品 0
海淀
程序员
私信 提问
Kotlin 写 Android 单元测试(三),Mockito mocking 框架的使用

Kotlin 写 Android 单元测试系列: Kotlin 写 Android 单元测试(一),单元测试是什么以及为什么需要 Kotlin 写 Android 单元测试(二),JUnit 4 测试框架和 kotlin.test 库的使用 Kotlin...

JohnnyShieh
2017/12/14
0
0
Mockito入门及配合Junit进行单元测试

声明:原创文章,转载请注明出处。http://www.jianshu.com/p/46afe8c54d34 一、背景 最近一段时间在给写的框架补单元测试。发现有一些方法做单元测试不好做,主要是其内部依赖了许多外部环境...

唐影若凡
2017/11/17
0
0
【腾讯Bugly干货分享】安卓单元测试:What, Why and How

本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d28349101cd07a5404c415 Dev Club 是一个交流移动开发技术,结交朋友,扩展人脉的社群,成员...

腾讯Bugly
2016/09/26
20
0
【腾讯Bugly干货分享】安卓单元测试:What, Why and How

本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d28349101cd07a5404c415 Dev Club 是一个交流移动开发技术,结交朋友,扩展人脉的社群,成员...

腾讯Bugly
2016/10/10
488
0
提升单元测试体验的利器--Mockito使用总结

为神马要使用Mockito?   在编写单元测试的时候,为了尽可能的保证隔离性,我们时常需要对某些不容易构造或者不容易获取或者对外部环境有依赖的对象,用一个虚拟的对象来创建以便于测试.假设你...

冬至饮雪
2017/06/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

乱入Linux界的我是如何学习的

欢迎来到建哥学Linux,咳!咳!咳!开个玩笑哈,我是一个IT男,IT界的入门选手,正在学习Linux。 在之前,一直想进军IT界,学习IT技术,但是苦于没有人指导,也不知道学什么,最开始我自己在...

linuxprobe16
32分钟前
0
0
OSChina 周日乱弹 —— 没时间 没头发 但有钱

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @开源中国总经办主任 :分享齐一的单曲《这个年纪》 《这个年纪》- 齐一 手机党少年们想听歌,请使劲儿戳(这里) @肿肿卷 :我真的可以睡一天...

小小编辑
今天
41
4
Django进阶 1.1 ORM基础—ORM 1.2.1 增删改查之查询 1.2.2 删改增 (1) 1.2.3 删改增 (2)

ORM基础 ORM是Django操作数据库的API,Django的作者将sql语句封装在里面供我们使用。 我们前面还提到过Django提供一个模拟数据库的工具,sqlite,供我们学习测试使用。 如果我们想使用mysql...

隐匿的蚂蚁
今天
3
0
Windows 上安装 Scala

在安装 Scala 之前需要先安装 Java 环境,具体安装的详细方法就不在这里描述了。 您可以自行搜索我们网站中的内容获得其他网站的帮助来获得如何安装 Java 环境的方法。 接下来,我们可以从 ...

honeymose
今天
3
0
数据库篇多表操作

第1章 多表操作 实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系...

stars永恒
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部