Android应用开发之Android单元测试中常见的问题和套路分享
凌雪 2018-09-20 来源 :网络 阅读 534 评论 0

摘要:本文将带你了解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频道!

本文由 @凌雪 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程