天天看点

在 MVP 中进行单元测试0. 提纲1. 什么是单元测试2. 单元测试的意义3. Android 开发中进行单元测试4 开源框架5. MVP 架构中如何写单元测试6. 例子

对于测试,大家都不陌生,但是我相信还是有部分开发觉得测试工作和自己没有直接关系、测试工作是测试工程师的事。惭愧的说,本人也是很长一段时间内没真正理解“测试”这件事儿,之前呆过的几家公司都没有真正的“测试工程师”,确切的说,是没有会写代码的测试工程师,基本上都是手动测试,然后输出报告,测试无需懂技术,我相信国内很多公司都是这样,特别是 app 端的测试,很少有白盒测试的。这篇要说的东西不多,主要来说说单元测试,由于本人也是最近才开始实践,文章抛砖引玉,如果有说得不到位的地方,希望读者给予指正。

0.1 什么是单元测试

0.2 单元测试的意义

0.3 android 开发中进行单元测试

0.3.1 androidstudio 中配置

0.4 开源框架

0.5 mvp 架构中如何写单元测试

0.6 例子

我们先来做这么一个体验。假设现在我们有个开发者要完成某个功能的开发,现在我们从电脑屏幕的视角来观察他接下来的一序列行为:

在这个观察中,我们看到他每次启动运行 a 所做的事其实就是“测试”,所以单元测试这件事其实是每个开发都做得最多的一件事,只是怎么让这件事变得更高效、更有意义是接下来要讲的。最后给出一个官方性的定义:单元测试又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。 程序单元是应用的最小可测试部件。

我们先来看看一张图:

在 MVP 中进行单元测试0. 提纲1. 什么是单元测试2. 单元测试的意义3. Android 开发中进行单元测试4 开源框架5. MVP 架构中如何写单元测试6. 例子

这张图叫做测试金字塔,单元测试处于开发环节比较早期,粒度也比较小,也是最重要的一个环节,对整体测试的效率至关重要,这部分做好了,后期的测试才会更有效,试想如果整栋楼建好了才发现砖头质量有问题,那是多么糟糕的事;单元测试就像对每个螺丝钉测试一样,生产螺丝钉的时候发现螺丝钉有问题很容易解决,如果在机器运转故障的时候去定位是不是螺丝钉、具体是那颗螺丝钉就难了。单元测试的意义可以总结如下几点:

代码质量的基础保障。

单元测试,模块区间比较小,更容易发现问题,发现问题更容易定位。

为后期集成测试节省了很多时间。

单元测试是对程序结构的一个观察者视角审视,有利于我们提高代码的整体设计能力。

android 为我们提供了两种跑测试的方式:

unit tests

android instrumentaion tests

在 MVP 中进行单元测试0. 提纲1. 什么是单元测试2. 单元测试的意义3. Android 开发中进行单元测试4 开源框架5. MVP 架构中如何写单元测试6. 例子

unit tests 这种方式,跑的测试代码运行在本机 jvm 上,不需要编译apk ,不需要 android 设备的支持,速度相对快,当然,测试的对象不能含有 android 的 api,否则运行时会报错。这个模式下,测试代码的默认路径是 test/java。单元测试的基础框架是 junit,需要配置依赖:

然后我们来写一个被测试类:calculator.java

把test artifact 切换到 unit tests 模式,然后我们创建一个针对这个类的测试:calculatortest.java

在 MVP 中进行单元测试0. 提纲1. 什么是单元测试2. 单元测试的意义3. Android 开发中进行单元测试4 开源框架5. MVP 架构中如何写单元测试6. 例子

选择 create new test

在 MVP 中进行单元测试0. 提纲1. 什么是单元测试2. 单元测试的意义3. Android 开发中进行单元测试4 开源框架5. MVP 架构中如何写单元测试6. 例子

自动生成了选择的测试方法,@before、 @after、@test 这几个注解来自 junit 的 api,@before 标记的方法,在测试用例启动时最先执行,然后执行 @test 标记的方法,最后执行 @after 标记的方法。一般会在 @before 的方法中做初始化工作,例如:创建被测试的对象, @test 标记的就是我们要测试的方法,在其中执行验证方法。完善我们的测试代码:

然后在这个类上右键,我们就可以运行这个测试类了。

android instrumentaion tests 包的测试代码运行在 android 设备上,速度相对慢一些。测试代码默认路径是 androidtest/java。为了让测试能跑在设备上,需要 androidjunitrunner 的支持:

配置依赖:

同时也离不开 junit 的支持,配置依赖:

创建测试和 unit tests 的一样,运行的时候需要连接模拟器或手机。

测试框架很多,这里只简单说说比较流行的组合以及本例子中要使用的框架:

espresso:google 提供的 u i测试框架。

理解了 androidstudio 中如何写最基本的单元测试,再结合几个开源框架,我们可以来写一些更为贴近实际开发的测试用例了。 目前 mvp 是 android 项目的比较流行的架构模式,它的优点在代码的易测性

上也得到了极好的体现,对 mvp 不熟悉的考验参考我之前的几篇博客:

<a href="http://www.jianshu.com/p/e157cc64ea5c">android 应用架构概述</a>

<a href="http://www.jianshu.com/p/101f756bf3b8">android应用架构之mvp实现</a>

对于 mvp 个层次我们怎么来写测试代码? 先来看看框架的选型:

view层

view的测试自然依赖于android环境,同时需要模拟u交互的能力,使用 espresso + junit,espresso用于模拟和验证各种各样的ui操作,使用 android instrumentaion tests 运行,代码存放于androidtest中。

presenter层

presenter 上对ui,下对 model 都是接口抽象,控制流程逻辑,不涉及 android api,用 junit + mockito 测试即可,使用 unit tests 运行,代码存放于test中。

model层

负责数据的存取,数据可能来自于网络、数据库和内存,如果涉及设备相关的api、依赖android系统环境,则使用 android instrumentaion tests 运行,代码存放于androidtest中;反之可以junit+mockito,使用 unit tests 运行,代码存放于test中。

## 6.1 场景介绍

这是一个简单的场景,一个游戏列表页面。对于列表页面,通常都会有缓存逻辑,加载数据时会优先去加载本地数据,如果没有,则加载远端数据。本例使用 mvp 来架构这个简单的场景(引入了 eventbus 来代替常规的异步回调,eventbus 极其简单,不过不理解也不影响对本章主题的理解),然后真对 m 和 p 分别写了对于的单元测试,本例没有写 view 层的单元测试(个人觉得对 view 写单元测试的必要性不大,如果你的感受相反,非常感谢你给我一个说服我的理由),我们先来流程图:

在 MVP 中进行单元测试0. 提纲1. 什么是单元测试2. 单元测试的意义3. Android 开发中进行单元测试4 开源框架5. MVP 架构中如何写单元测试6. 例子
在 MVP 中进行单元测试0. 提纲1. 什么是单元测试2. 单元测试的意义3. Android 开发中进行单元测试4 开源框架5. MVP 架构中如何写单元测试6. 例子

test/java :该目录下写了针对 gamepresenter 的单元测试 gamepresentertest 和针对 gamemanager 的测试类 gamemanagertest (这个跑不过,因为涉及类 android 的 api)

androidtest / java: 该目录下写 针对 gamemanager 的测试类 gamemanagerandroidtest (逻辑和 gamemanagertest 一样)

@mock :对成员变量的注解,被这个注解的变量不用手动实例化,mockito 会帮你注入一个模拟的对象(需要在 @before 标记的方法中先执行 mockitoannotations.initmocks(this)。例如:

初始化 mockitoannotations

verify(t):这是 mockito api 提供的一个静态方法,用来验证某个 mock 对象(@mock 标记的对象)是否执行了某个方法,执行了多少次。verify(t),返回是一个泛型,你传入什么类型他就返回什么类型的子类给你,重写的方法中验证传入对象对应的方法是否执行过。例如:

//验证 gamelistview.showloading() 是否执行

when(object.method()).thenreturn(returnobject): 这是 mockito api 提供的一个静态方法,用来改变方法的对象的行为(方法),当 object.method() 调用的时候返回 returnobject ,用来模拟方法的返回值。例如本例中模拟获取本地数据为空:

继续阅读