安卓单元测试全攻略

本文详细介绍了如何在安卓应用中进行单元测试,包括Model层、View层的测试方法。使用Junit、Mockito和Robolectric实现从M层到V层的全面测试,确保100%覆盖率。讲解了如何通过Mockito模拟对象、验证参数和响应状态,以及如何使用Robolectric进行UI单元测试,避免依赖安卓设备。此外,还提到了数据转换类的测试,以及针对Presenter层的测试策略,强调了单元测试的重要性及其时间节省效应。
摘要由CSDN通过智能技术生成

安卓单元测试,只看这一篇就足够啦。真正的完全解析,真正的从0到1,Junit结合Mockito与Robolectric实现从M层到V层,Jacoco扫描函数、逻辑、代码行数单元测试覆盖率100%的全面测试。你是否还在为了验证联网与未联网状态而频繁的开关WiFi开关?或者你是否还在为一个switch判断而频繁的使用debug断点setValue来观测代码的逻辑判断情况?又或者你是否还在为了校验某个UI文案的正确性而反复的比对UI稿?可能你会反问,难道写完代码自测也有错?当然不是,自测是一个良好的习惯,不过作为一名工程师,你要做的不应该只是看看点点的黑盒测试,而是应该设计出一套能够让代码测试代码,一劳永逸的测试工程。

首先我们从Model层开始,通过具体代码来详尽说明一下一个单元测试覆盖率100%的测试工程是如何建立的。严格意义上讲,Model数据层负责数据加载与储存,是游离于安卓环境之外的存在,所以它可以不需要借助安卓SDK的支持。使用Junit结合Mockito即可做到100%条件分支覆盖率的单元测试。如果项目的Model层有安卓依赖,可能就表明此处的代码需要重构了,这也是单元测试其中的一个意义,让代码逻辑更清晰。清除Model层的安卓依赖的另一层面好处是让测试case更高效,我们都知道在不借助UI单元测试框架的情况下在测试case中使用安卓依赖会抛出RuntimeException原因是我们的IDE与SDK只提供了项目的开发和编译环境,并没有提供运行环境,所以直接引用安卓相关代码的时候就会抛出异常。为此,谷歌官方提供了Espresso测试框架,但Espresso的有着运行需要借助安卓设备,运行时间过长,Jenkins自动化集成困难等问题,最终只能放弃了对官方框架的使用。而是采用Robolectric框架作为UI单元测试的核心。即便如此,运行测试case的时间也需要5秒以上,但对于一个没有安卓依赖的Model类,跑完全部case的时间可以降低至毫秒级。所以,去除Model层所不需要的安卓依赖还是很有必要的。

这里写图片描述

Model层完整测试代码如下:


/**

* Author : YangHaoyi on 2017/6/30.

* Email  :  yanghaoyi@neusoft.com

* Description :MVP---M test case example.

* Change : YangHaoYi on 2017/6/30.

* Version : V 1.0

*/

@RunWith(MockitoJUnitRunner.class)

public classWeatherModelTest {

privateWeatherModelmodel;

@Mock

ApiServiceapi;

@Mock

WeatherDataConvertconvertData;

@Mock

WeatherRequestListenerlistener;

private static finalStringJSON_ROOT_PATH="/json/";

privateStringjsonFullPath;

privateWeatherDatanetData;

privateMapqueryMap;

@Before

public voidsetUp() {

RxUnitTestTools.openRxTools();

model=newWeatherModel();

}

@Test

@SuppressWarnings("unchecked")

public voidtestParams() {

model.request(listener,"沈阳");

try{

Field fieldParam = WeatherModel.class.getDeclaredField("queryMap");

Field fieldKey = WeatherModel.class.getDeclaredField("CITY");

fieldParam.setAccessible(true);

setFinalStatic(fieldKey, true);

Map queryMaps = (Map) fieldParam.get(model);

String key = (String) fieldKey.get(model);

assertEquals("验证queryMap的Key",key,"city");

String city = queryMaps.get("city");

assertEquals("验证queryMap的value",city,"沈阳");

}catch(Exception e) {

//reflect error

}

}

@Test

@SuppressWarnings("unchecked")

public voidtestRequestSuccess() {

initResponse();

Mockito.when(api.getWeather(queryMap)).thenReturn(Observable.just(netData));

ArgumentCaptor captor = ArgumentCaptor.forClass(WeatherData.class);

model.request(listener,"沈阳");

Mockito.verify(api).getWeather(queryMap);

Mockito.verify(listener).showLoading();

Mockito.verify(listener).hideLoading();

Mockito.verify(convertData).convertData(captor.capture());

WeatherData result = captor.getValue();

intstatus = result.getStatus();

assertEquals("验证code",status,1000);

}

@Test

public voidtestStatusError() {

initResponse();

netData.setStatus(1001);

Mockito.when(api.getWeather(queryMap)).thenReturn(Observable.just(netData));

ArgumentCaptor captor = ArgumentCaptor.forClass(WeatherData.class);

model.request(listener,"沈阳");

Mockito.verify(api).getWeather(queryMap);

Mockito.verify(listener).showLoading()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值