为了账号安全,请及时绑定邮箱和手机立即绑定

目前最全面的Android Espresso配置指南了

标签:
Android

安卓开发过程中测试的编写是一个公认的痛点,本文总结了我在AndroidTDDBootStrap工程中配置Espresso测试所遇到的坑,例如神秘报错android.content.res.Resources$NotFoundExceptionjava.util.zip.ZipException: duplicate entry,以及对dagger,mock网络请求的实践,目测应该是目前最全面的指南了 :) 本文涉及的完整代码可以在Github: AndroidTDDBootStrap获取。

配置Gradle依赖

app/build.gradle中加入以下配置:

[代码]xml代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

androidTestCompile project(':testbase')

androidTestCompile   (appTestDependencies.androidJUnitRunner) {

    exclude module:   'support-annotations'

}

androidTestCompile   (appTestDependencies.mockito) {

    exclude module:   'hamcrest-core'

}

androidTestCompile   appTestDependencies.dexmaker

androidTestCompile   (appTestDependencies.dexmakerMockito) {

    exclude module:   'hamcrest-core'

    exclude module:   'mockito-core'

}

androidTestCompile   (appTestDependencies.androidJUnit4Rules) {

    exclude module:   'support-annotations'

    exclude module:   'hamcrest-core'

}

androidTestApt   (appDependencies.daggerCompiler) {

    exclude module:   'dagger'

}

androidTestCompile就是用来声明安卓instrumentation测试的依赖的,它对应的gradle测试命令是./gradlew :app:connectedAndroidTest或者./gradlew :app:cAT。而androidTestApt则是在instrumentation测试代码中使用apt插件生成代码的(dagger2用到)。

在这里我还遇到了两个特别诡异的错误,第一个是运行测例直接失败,logcat报错如下:

[代码]xml代码:

?

1

android.content.res.Resources$NotFoundException:   Resource ID

Google几番也没有找到什么头绪,最后从StackOverflow上一个回答的评论中找到了原因:归根结底还是因为发生了重复依赖!通过./gradlew :app:dependencies分析app的依赖,发现testbase这个module依赖了appcompat-v7,而app则直接编译依赖了它,两者在instrumentation测试中发生了冲突,导致了这个诡异的闪退,移除testbaseappcompat-v7的依赖之后就解决了这个问题。

第二个是执行./gradlew :model:cAT失败,gradle报错如下:

[代码]xml代码:

?

1

java.util.zip.ZipException: duplicate   entry:      javax/annotation/Generated.class

同样是几番Google无果,反复折腾了几天,无奈只能自行分析。从报错来看还是发生了依赖重复,存在两个javax/annotation/Generated.class类,通过./gradlew :model:dependencies分析model的依赖,最终发现testbase这个module通过espresso间接依赖了javax.annotation-api,而model则通过base编译依赖了javax.annotation,两者发生了重复,导致了这个问题。通过配置testbase,在依赖espresso的时候exclude module: 'javax.annotation-api'终于解决了这个问题。

依赖注入

如何为测试代码配置依赖注入这个问题已经纠缠我两年了。

最初听从了某大神的博客建议,debug和release两个variant用作不同用途,debug一套DI的代码,专门用于测试,release一套DI的代码,专门用于非测试(博客出处已经不可考了)。这种方式最大的问题就是需要维护两套代码,而且他们无法同时被IDE展示(必须通过build variant切换),在重构的时候无法同时重构,经常导致重构了业务代码,结果测试代码没有被重构,必须手动修改,非常蛋疼。

后来参考了另一位大神Chiu-Ki的博客,采取了Application类暴露接口设置dagger component的方式,设置进去的component负责提供mock的对象,并且它可以把依赖注入到测试代码中。这种方式比较简洁,但是Application类却暴露了不应该暴露的接口,不是十分优雅。

最终Chiu-Ki再次发力,通过编写一个MockApplication类,并通过自定义Test Runner来启动mock application,完美解决了这一问题。mock application类继承自application类,在其中初始化component为提供mock的component,而mock component又把依赖注入到测试代码中,完美 :)

但是dagger在涉及到继承的时候有一个细节需要注意:如果component定义的inject接口接受的是父类型,那么当子类型实例调用inject(this)时,子类型中需要注入的依赖(@Inject注解的成员)将无法注入!需要编写一个component的子类,把inject接口的参数类型声明为子类型,并且声称component子类的实例进行依赖注入。这种情况下父类中需要注入的依赖是可以成功注入的,因为dagger可以搜索父类并把依赖注入到父类中,但反过来是行不通的,dagger是无法搜索子类并注入依赖到子类中的(因为编译期间可能根本就无法获取到子类的符号呀,怎么能搜索子类呢?)。

Mock网络请求

可以说目前最流行的网络请求库就是OkHttp了,而且从安卓6.0开始它就是系统的默认实现了。而OkHttp还提供了另一个无比强大的工具:MockWebServer。而OkHttp + Retrofit应该是REST API请求的标配了,下面我就总结一下如何利用MockWebServer来进行网络请求mock,对APP进行集成测试。

Retrofit 2.0中没有了end point的概念,取而代之的是base url,在创建Retrofit对象的时候可以配置,在测试中我们配置base url为http://localhost:9876/,同时在测试用例中我们配置MockWebServer运行在9876端口。这样任何通过Retrofit发起的API调用都是请求的MockWebServer了。

MockWebServer可以设置Dispatcher,可以根据不同的请求返回不同的数据,在本工程的一个测例中,dispatcher的设置如下:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

new Dispatcher() {

    @Override

    public MockResponse dispatch(final RecordedRequest request)

            throws InterruptedException {

        final String path = request.getPath();

        if (path.startsWith("/search/users?"))   {

            return new MockResponse().setBody(

                    MockProvider.provideSimplifiedGithubUserSearchResultStr());

        }   else {

            return new MockResponse();

        }

    }

};

如此通过Retrofit调用/search/users接口返回的就是mock的数据了。完美 :)

原文链接:http://www.apkbus.com/blog-705730-60573.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消