Android 单元测试实战—— 调研与选型
Posted Alex_MaHao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 单元测试实战—— 调研与选型相关的知识,希望对你有一定的参考价值。
android 单元测试实战(1)—— 调研与选型
单元测试搞了一段时间,发现网上很多关于单元测试的文章都是讲了概念,讲了框架的使用,但对于一个实际的项目的操作,因为项目的复杂性,框架的稳定性等,确往往无法进行。本篇博客从实际出发,基于实际的项目总结而出。
本系列文章不会涉及到单元测试的概念,以及它的各种现实意义。仅从实现入手,关于它的优劣不做分析。
单元测试系列会分为三篇博客:
- Android单元测试调研与选型
- 基于
Powermock
的Android单元测试常用方法指南 - 基于
Cobertra
&sonarqube
的单元测试覆盖率统计
调研与选型
Google
官方文提供了单元测试的支持。在创建项目的时候会默认创建test
和androidTest
目录。分别是单元测试和集成测试。单元测试是对方法的测试,粒度较小,无需运行在真机上。集成测试需要每次运行需要跑在真机上,粒度较大,运行时间较长,而且不利于一些自动化的工作。
本系列的核心从单元测试入手,以自动化为目的。
单元测试一个绕不开的话题就是对于android.jar
的问题。由于android.*
的官方类,在运行单元测试的时候,只有方法的声明,内部的所有方法都会throw new RuntimeException('Stub')
。那么一旦有调用官方类的地方,比如View
,Intent
,Activity
等,就会报错,导致单元测试无法执行。
一种常见的解决方式是通过架构来解决,将一些代码逻辑和官方类解耦,比如MVP
,对Presenter
做测试,因为大部分逻辑都在Presenter
,所以还ok。
但是不幸的,一般搞单元测试的时候,很难是从一个新项目入手的,架构很难变动,一旦修改架构,影响范围比较广。
而我们的项目就是这样的,所有的逻辑都在Activity
中编写,一旦测试逻辑就肯定绕不开官方类。
官方文档上提到了单元测试的两种解决方案。
一种是通过Mock
来解决,及将官方类的调用方法给代理一下,不会实际的调用官方类的相关方法。
另外一种是Robolectric
,该框架通过在jvm
上模拟android
虚拟机,以单元测试的方式来完成集成测试。
Robolectric
(放弃)
因为最终没有使用这个框架,所以先介绍一下这个框架。
该框架相当于是搭建了一个android
虚拟机,其运行单元测试的时候,实质是运行了一个app
。那么其做测试的逻辑更倾向于appium
等的UI
测试,查询一个控件,模拟点击,验证逻辑。
因为其模拟的虚拟机,那么他对官方的方法做了扩展,提供了一些列的ShadowXXX
类,便于做验证和模拟。比如获取当前弹出的dialog
,最后一个弹出的toast
等等。
调研的时候,该框架最新版本为4.3
,并且从4.0
开始,已经开始和官方的androidx.test
下测试库进行兼容。可以通过官方espresso
完成一些列操作。那么一套代码,技能在控制台运行,又能在模拟器上运行,想想还是挺美好的。
但是 !!!
因为我们的项目都是在Activity
里面写的,一些业务逻辑都是使用私有方法,那么相对私有方法做验证,通过查询控件和通过UI
的展示来验证逻辑的正确与否,十分的复杂。
举个例子:
@Override
public void onClick(View v)
switch (v.getId())
case R.id.skip:
startNextActivity(false);
break;
case R.id.splash_image:
startNextActivity(true);
break;
default:
break;
private synchronized void startNextActivity(boolean isClick)
我想验证不同的View
点击,调用的startNextActivity
的参数是否正确。如果从UI
上验证十分的复杂,而且万一startNextActivity
的内部逻辑有问题,或者比较巧妙,那么UI
的验证也不一定准确。
有方法解决吗??肯定有,便是Mock
,这个后面会说。
能够Mock
私有方法的常用的是Powermock
,但是!!!!!
该框架和Robolectric
存在着各种兼容问题,在我头发掉了一地之后,也没有解决。
所以放弃了!!!!注意是放弃了Robolectric
!!!!
Mock (使用)
mock
是单元测试中常用的一种方式,通过对即将调用方法的修改,模拟调用方法的返回值等等,具体的概念百度上一大堆。我就不再这里废话了。
官方文档上建议使用Mockito
完成mock
操作,但是该库不支持静态方法,私有方法,final
等的mock
。
上面提到了Powermock
,他提供更加强大的mock
功能,而且它提供了Mockito
的支持,使用上和Mockito
基本上一样。
比如说,对于上面的代码,使用Powermock
方法验证逻辑如下:
@Test
public void onClickSkip() throws Exception
// mock activity, activity的所有方法都不会被执行
LauncherActivity activity = PowerMockito.mock(LauncherActivity.class);
// 指定activity的onClick不被`mock,调用真实的逻辑,以便进行单元测试
PowerMockito.doCallRealMethod().when(activity, "onClick", ArgumentMatchers.any(View.class));
// Mock 官方类
View view = PowerMockito.mock(View.class);
// 指定getId的返回值
PowerMockito.doReturn(R.id.skip).when(view, "getId");
// 调用测试的方法
activity.onClick(view);
// 验证指定的方法和参数是否被滴啊用
PowerMockito.verifyPrivate(activity).invoke("startNextActivity", false);
代码注释很清楚,不在废话。
按照上面的思路,其实可以验证大部分的单元测试逻辑。
总结
综上所述,决定使用Powermock
为基础,完成单元测试的编写。
以上是关于Android 单元测试实战—— 调研与选型的主要内容,如果未能解决你的问题,请参考以下文章
Android 单元测试实战—— 基于Powermock的常用方法指南
Android 单元测试实战—— 基于Powermock的常用方法指南
Android 单元测试实战—— 基于Cobertra&sonarqube的单元测试覆盖率统计