摘要:本文将带你了解Android应用开发之Android单元测试中常见的问题和套路分享,希望本文对大家学Android有所帮助。
本文将带你了解Android应用开发之Android单元测试中常见的问题和套路分享,希望本文对大家学Android有所帮助。
前言
最近开始给公司的项目写单元测试,先从已经抽离成库的类开始写,因为不会涉及到界面,所以目前写起来较为容易。
单元测试框架采用的是 powerMock 框架,不过在写的过程中,发现了一些问题,今天我们就说一下一些常见的问题,和对某些类型代码常见的套路(针对这种类型应该如何编写单元测试用例)。
常见问题
1、android 类方法调用为空,Method isEmpty in android…
Android 相关类依赖的环境是 Android 虚拟机,而我们不在真机上做单元测试的时候,依赖的是 JVM 环境,这时候我们可以主动创建需要类的方法。
举个例子:
?1234567public HttpRequest getProductSearch(String url){ if(TextUtils.isEmpty(url)){ return null; } return new HttpRequest(url);}
假设这是我们要测的类,正常来说我们我们可以这样做单元测试
?12345678@Testpublic void TestGetProductSearch(){ HttpSetting httpSetting = new HttpSetting(); HttpRequest request = httpSetting.getProductSearch("url"); Assert.assertNotNull(request); }
然后美滋滋的运行一下,发现
这就是我们在 JVM 的环境里找不到 TextUtils.isEmpty() 这个方法,这时候我们就可以手动创建这个方法,注意包名要正确:
再次运行测试用例,即可得到通过的结果。
2、Wanted but not invoked:
先看一下要被测试的代码,在 HttpSetting 类里面:
?123456public void getCart(User user){ user.setName("hello"); user.setPin("world"); }
然后我们想要验证这个方法内 User 的行为,有时候会这样写:
?12345678@Testpublic void TestGetCart(){ User user = mock(User.class); HttpSetting httpSetting = mock(HttpSetting.class); httpSetting.getCart(user); Mockito.verify(user).setName("hello"); Mockito.verify(user).setPin("world");}
再一次美滋滋的点下运行,然后发现:
这个错误日志是说验证的代码中,其实没有交互,但是我们被测试明明有交互,那么到底问题出在哪里呢?其实问题就出在了下面这行代码中:
?1HttpSetting httpSetting = mock(HttpSetting.class);
mock(HttpSetting.class) 在我看了其实就是模拟这个类,并且记录行为,但是并不会真正执行一些逻辑,所以你直接调用 mock 出来类的方法,只会产生一个记录,并不会真正执行里面发生的逻辑,导致了出现的错误提示,所以我们把那行代码改成下面这样,即可解决问题。
?1HttpSetting httpSetting = new HttpSetting();
还有一种情况,就是你用到了 PowerMock 特性,但是并没有加上下面两行注解内容,这样加上对应的注解就行
?123@RunWith(PowerMockRunner.class)@PrepareForTest( {用到的类名.class })public class XXX
3、org.powermock.reflect.exceptions.FieldNotFoundException:
这个问题笔者在 stackoverflow 上看到的答案基本都是 PowerMock 库版本号低,相对于 Mockito 库的版本。
发生错误时,笔者导入的相关库的版本:
?12345testCompile 'org.mockito:mockito-core:1.9.5'// required if you want to use Powermock for unit teststestCompile 'org.powermock:powermock-module-junit4:1.5.6'testCompile 'org.powermock:powermock-module-junit4-rule:1.5.6'testCompile 'org.powermock:powermock-api-mockito:1.5.6'
当我把 powermock 三个相关库的版本改成 1.6.5 后再运行一下测试用例,这个错误果然消失了。
针对套路
1、方法内部 new 对象如何 Mock,验证其行为
还是先看下要被测试的代码
?123456public void initMall(){ Mall mall = new Mall(); mall.setCode("123456"); mall.setLogo("tree"); mall.setName("I am Groot");}
起先我看到类似的代码我是懵逼的,完全不知道怎样去测,幸亏在偶然间看到了 PowerMock 强大特性介绍,发现其中竟然可以模拟构造函数,使构造函数返回我们 mock 出来的对象,从而验证其发生的行为。
下面我们看测试用例代码
@Testpublic void TestInitMall() throws Exception{ Mall mall = mock(Mall.class); whenNew(Mall.class).withAnyArguments().thenReturn(mall); HttpSetting httpSetting = new HttpSetting(); httpSetting.initMall(); Mockito.verify(mall).setCode("123456"); Mockito.verify(mall).setLogo("tree"); Mockito.verify(mall).setName("I am Groot");}
关键代码是
whenNew(Mall.class).withAnyArguments().thenReturn(mall);
这行代码含义是当你以任何参数创建出来的这个类,都会返回我指定的类的实例,当然也可以指定参数,或者没有参数,返回指定的类实例。
2、需要验证的方法内部有类私有变量怎么办
这种情况也很常见,随便写一个被测试的代码来看看
private TimeLimit timeLimit = new TimeLimit(); public String getLimitTime(){ //这里我们假设 timeLimit.getCurrentTime() 肯定会返回一个不为空的值 return timeLimit.getCurrentTime();}
随意点的单元测试用例,可能会写出下面的测试代码
@Testpublic void TestGetLimitTime(){ HttpSetting httpSetting = new HttpSetting(); String limitTime = httpSetting.getLimitTime(); Assert.assertNotNull(limitTime);}
随便验证一下返回结果不为空就可以了,但是如果我们想更加详细的测一下,验证是否是通过 TimeLimit 拿到的结果,这时我们就可以这样做
@Testpublic void TestGetLimitTime(){ TimeLimit timeLimit = mock(TimeLimit.class); when(timeLimit.getCurrentTime()).thenReturn("1"); HttpSetting httpSetting = new HttpSetting(); Whitebox.setInternalState(httpSetting,"timeLimit", timeLimit); String limitTime = httpSetting.getLimitTime(); Assert.assertNotNull(limitTime); Mockito.verify(timeLimit).getCurrentTime();}
通过下面这行代码可以指定类实例的私有变量
?1Whitebox.setInternalState(httpSetting,"timeLimit", timeLimit);
这里 Junit 验证结果和 Mockito 验证行为有些冲突,因为是 mock 的对象,所以如果不指定方法行为,将会返回空,就不会通过 Assert.assertNotNull(limitTime)
3、如何 mock 类的部分方法
当你在测试一个类的一个方法时,这个类又调用了该类的另一个方法时,如果这个方法很复杂,不想执行内部逻辑,只需要返回一个什么结果的时候就可以模拟这个方法。
我们简单看下示例代码:
要被测试的类方法:
public void login(String pin){ if(checkUser(pin)) { User user = new User(); user.setPin(pin); user.doLogin(); }} public boolean checkUser(String pin){ //假设执行了各种复杂逻辑 return true;}
然后是单元测试代码
@Testpublic void TestLogin() throws Exception{ HttpSetting httpSetting = new HttpSetting(); HttpSetting spy = PowerMockito.spy(httpSetting); User user = mock(User.class); whenNew(User.class).withNoArguments().thenReturn(user); when(spy.checkUser("hello world")).thenReturn(true); spy.login("hello world"); Mockito.verify(user).setPin("hello world"); Mockito.verify(user).doLogin();}
单元测试的常见问题和套路今天就先分享到这,对 Android 中的单元测试感兴趣的可以关注本人以前和以后分享的文章。
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注移动开发之Android频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号