Android单元测试

单元测试业界标准:
MVP + Junit4 + Mockito + Hamcrest + Espresso + Dragger2

一、为何要做单元测试

  1. App持续集成的时候需要一个集成测试保障其正确性(正确性)
  2. 页面较复杂的时候,我们是否可以先测试业务逻辑的正确性(边开发边测试)
  3. 项目较大,编译缓慢,测试业务逻辑部分(测试速度大幅提高)
  4. 对代码结构、代码健壮性、代码可维护度都有很大提高
  5. 不用太担心修改代码后,会导致其它bug,单元测试集成测试会告诉我们

    other:蘑菇街的哥们说过:慢慢的你会发现,其实不是这样的,纯java的代码其实真不少,而且往往是核心的逻辑所在

二、测些什么

代码结构:

Android中的MVC分层不清晰,我们更倾向于MVP,这里列举一些比较好的文章。

测试框架:

Android单元测试分为:

Local Unit Tests (直接在JVM上进行测试):
  1.Junit4
  2.Mockito (最常用的Mock之一)
  3.Hamcrest(增加JUnit的测试能力)
  4.Robolectric(第三方:JVM中模拟Android)
Instrumented Tests (需要借助仪器、模拟器测试):
  1.AndroidJUnitRunner (官方:InstrumentTestRunner升级版,支持Junit4,下面的UI测试框架需要与之结合使用)
  2.Espresso (官方:测试单独App)
  3.UI Automator (官方:跨进程测试(多App之间进行测试))
  4.Robotium(第三方:基于Android 原生的Instruments)
  5.Appium (第三方:支持Android IOS自动化测试)

  • OS: Apple’s UIAutomation
  • Android 4.2+: Google’s UiAutomator
  • Android 2.3+: Google’s Instrumentation. (Instrumentation support is provided by bundling a separate project, Selendroid)

测些什么

  • Local Tests 测试业务逻辑层、部分Model层
  • Instrumented Tests 测试UI,测试用例
  • 测试方法的返回值
  • 测试操作流程中方法的调用情况(是否调用?调用几次?被调用时传入的参数值)

三、测试准备

1. Junit4

2. Mockito

Mock的概念(Mockito.mock):所谓的mock就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,以达到两大目的:
- 验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等
- 指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作
- 注意:需要将Mock对象注入到需要测试的类中

@RunWith(MockitoJUnitRunner.class)
@Mock > (Mock出一个对象,此对象的方法调用并不会真正调用)
@Spy > (Spy出的对象,调用其方法会真正执行)
@Captor > (用于抓取被调用方法的参数,进行验证,也可以使用ArgumentCaptor new出来)
@InjectMocks > (只要在被测试类上标记@InjectMocks,Mockito就会自动将标记@Mock、@Spy等注解的属性值注入到被测试类中。)

// 抓取mock对象方法的参数进行验证:
// 验证mTasksRepository对象调用了getTask,并且抓取此方法的第二个参数
verify(mTasksRepository).getTask(eq(testTask.getId()), mGetTaskCallbackCaptor.capture());

// 调用上一步抓取到的参数的onTaskLoaded方法
mGetTaskCallbackCaptor.getValue().onTaskLoaded(testTask);
// 预设mock对象某方法被调用时返回特定值:
Mockito.when(searchSchoolFragmentView.isActive()).thenReturn(true);
// 预设mock对象某方法被调用时执行doAnswer里面自定义的逻辑:
// 也可以先
Mockito.doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        //这里可以获得传给performLogin的参数
        Object[] arguments = invocation.getArguments();

        //callback是第三个参数
        NetworkCallback callback = (NetworkCallback) arguments[2];

        callback.onFailure(500, "Server error");
        return 500;
    }
}).when(mockUserManager).performLogin(anyString(), anyString(), any(NetworkCallback.class));

3. Hamcrest

Assert.assertThat(object,Matcher.xxxmethod(yy));
Matchers:匹配器 > Espresso也基于此
 

4. Espresso

组成部分:

  • ViewMachers:寻找用来测试的View
  • ViewAction:发送交互事件
  • ViewAssertions:检测测试结果

View Machers: withId、withHint、allof(withId(),withHint())…
View Actions: click()、doubleClick()、pressBack()、openLick()…
View Assertions: matches、not、isDisplayed…

线程安全保障:

Espresso测试有个很强大的地方是它在多个测试操作中是线程安全的。

Espresso会等待当前进程的消息队列中的UI事件,并且在任何一个测试操作中会等待其中的AsyncTask结束才会执行下一个测试。这能够解决程序中大部分的线程同步问题。

Espresso中有个API叫做registerIdlingResource,它可以让你使用自定义的线程安全逻辑。(上面链接中有对registerIdlingResource详细讲解)

四、参考资料

蘑菇街小创
http://chriszou.com/

Android单元测试
http://www.chriszou.com/2016/04/13/android-unit-testing-start-from-what.html

解读Android官方MVP项目单元测试
http://www.jianshu.com/p/cf446be43ae8

Android官网测试文档
http://developer.android.com/intl/zh-tw/training/testing/start/index.html

dragger2:
(一)http://www.jianshu.com/p/cd2c1c9f68d4
(二)http://www.jianshu.com/p/1d42d2e6f4a5
(三)http://www.jianshu.com/p/65737ac39c44
dragger2:
http://www.cnblogs.com/tiantianbyconan/p/5092525.html

Android谷歌官方测试demo:
https://github.com/googlesamples/android-testing

Mockito讲解
http://www.vogella.com/tutorials/Mockito/article.html
Mockito更详细讲解
http://hotdog.iteye.com/blog/search?query=Mockito

Espresso
http://blog.csdn.net/shandong_chu/article/details/47083753

Espresso IdlingResource
http://www.jianshu.com/p/95d075b90a2f

MVP快速开发框架Beam
https://github.com/Jude95/Beam

encleus简化MVP
https://github.com/konmik/nucleus

五、下一篇文章以Android官方MVP架构示例项目解析谈测试

Android官方MVP项目单元测试分析得很到位

发布了39 篇原创文章 · 获赞 9 · 访问量 9万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章