3.解决内部new对象
小白:“我在Presenter里new Model,Model依赖比较多,会做sql操作,等等.....Presenter依赖Model返回结果,导致Presenter没法单元测试啦!求大神指点!”
小白C的例子:Model:
Presenter:
错误的单元测试:
还是那句话:依赖隔离。我们隔离Model依赖,即mock Model对象,而不是new Model()。
找找以上PresenterTest的问题吧:PresenterTest完全不知道Model的存在,意思是无法mock Model。那么,我们就想办法把mock Model传给Presenter——在Presenter构造函数传参!
改进Presenter:
正确的单元测试:
事情就这么解决了。如果你觉得在Activity直接用默认Presenter构造函数,在构造函数new Model()比较方便,那就保留默认构造函数呗。当然使用dagger2就不存在多个构造函数了,都是构造传参。
4.静态方法
小白:“大神,我在Presenter用到静态方法....”笔者:“行了,知道你要说什么。”
解决方法跟上面【解决内部new对象】大同小异,核心思想还是依赖隔离。
1).把sign(...)改成非静态方法;
2).把SignatureUtils作为成员变量;
3).构造方法传入SignatureUtils;
4).单元测试时,把mock SignatureUtils传给Presenter。
改进后Presenter:
5.RxJava异步转同步
小白:“大神...”
笔者:“为师掐指一算,料汝会遇此劫难。”
小白:(传说中从入门到出家?)
单元测试
运行RxPresenterTest:
你会发现没有输出"test",为什么呢?
由于testRxJava里面,Obserable.subscribeOn(Schedulers.io())把线程切换到io线程,并且delay了1秒,而testTestRxJava()单元测试早已在当前线程跑完了。笔者试过,即使去掉delay(1, TimeUnit.SECONDS),还是不会输出‘test’。
可以看到笔者把.observeOn(AndroidSchedulers.mainThread())注释掉了,我们把那句代码加上,再跑一下testTestRxJava(),会报java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked.:
这是由于jdk没有android.os.Looper这个类及相关依赖。
解决以上两个问题,我们只要把Schedulers.io()&AndroidSchedulers.mainThread()切换为Schedulers.immediate()就可以了。RxJava开发团队已经为大家想好了,提供了RxJavaHooks和RxAndroidPlugins两个hook操作的类。
在RxPresenterTest.setUp()加一句RxTools.asyncToSync();:
再跑一次testTestRxJava():
总算输出"test",感谢上帝啊!(应该打赏下笔者吧^_^)
读者有没发现RxTools.asyncToSync()多加了一句RxJavaHooks.setOnComputationScheduler(schedulerFunc),意思将computation线程切换为immediate线程。笔者发现,仅仅添加RxJavaHooks.setOnIOScheduler(schedulerFunc),对于有delay的Obserable还是未通过,于是顺手把computation线程也切换了,于是就可以了。
还有RxJavaHooks.reset()和RxAndroidPlugins.getInstance().reset(),笔者发现,当运行大量单元测试时,有些会失败,但单独运行失败的单元测试,又通过了。百思不得其解后,添加了那两句.....可以了!
(关于RxJavaHooks和RxAndroidPlugins的使用,在很久前的文章 《(MVP+RxJava+Retrofit)解耦+Mockito单元测试 经验分享》已经提及过)
小结
笔者:“小白同学,现在你踩过的坑,填好未?”
小白:“方丈,啊不,大神,上面几个问题是解决了,不过还有其他问题。”
笔者:“不挖坑,怎么填坑呢?以后再给你讲讲其他单元测试的玄机。”
小白:“......”
本文详述了几个单元测试重要问题的解决方法,读者不难发现,笔者一直强调 依赖隔离、依赖隔离、依赖隔离,这个概念在单元测试中相当重要。还搞不懂这个概念的同学,看多几次《Android单元测试 - 如何开始?》(又厚颜无耻地广告),同时在实践中不断回顾这个理念。
只要解决好这几个问题,Presenter单元测试就不难了。还有本文未提及的sqlite、SharedPreferences单元测试、在后面的文章会给读者介绍下。
感谢读者对笔者一直以来的支持,麻烦点赞&随手转发,好人一世平安。