千家信息网

Android单元测试中重要的问题有哪些

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,本篇内容主要讲解"Android单元测试中重要的问题有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Android单元测试中重要的问题有哪些"吧!1.
千家信息网最后更新 2026年11月02日Android单元测试中重要的问题有哪些

本篇内容主要讲解"Android单元测试中重要的问题有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Android单元测试中重要的问题有哪些"吧!

1.如何解决Android依赖?

小白:"Presenter中用到TextUtils,运行junit时报'java.lang.RuntimeException: Method isEmpty in android.text.TextUtils not mocked'错误... 是不是要用robolectric?"

别急,还未到robolectric出场的时候呢!

由于junit运行在jvm上,而jdk没有android源码,所以TextUtils这些在android sdk中的类,运行junit时就引用不上了。既然jdk没有,我们就自己加呗!

在test/java目录下,创建android.text.TextUtils类

  1. package android.text;

  2. public class TextUtils {

  3. public static boolean isEmpty(CharSequence str) {

  4. if (str == null || str.equals("")) {

  5. return true;

  6. }

  7. return false;

  8. }

  9. }


关键是要个TextUtils同包名、同类名、同方法名。注意不是在main/java下创建,不然会提示Duplicate class found in the file...。单元测试运行妥妥的:

原理很简单,jvm运行时会找android.text.TextUtils类,然后找isEmpty方法执行。学过java反射的同学都知道,只要知道包名类名,就可以拿到Class,知道该类某方法名,就可以获取Method并执行。jvm也是类似的机制,只要我们给一个包名类名与android sdk相同的类,写上方法名&参数&返回值相同的方法,jvm就能编译并执行。

(提示:android的View之类也能这么搞噢)

2.隔离Native方法

小白:"我用到native方法,junit运行失败,robolectric也不支持加载so文件,怎么办?"

Model类:

package com.test.unit;  public class Model {     public native boolean nativeMethod(); }

单元测试:

public class ModelTest {      Model model;      @Before     public void setUp() throws Exception {         model = new Model();     }      @Test     public void testNativeMethod() throws Exception {         Assert.assertTrue(model.nativeMethod());     } }

run ModelTest... 报错java.lang.UnsatisfiedLinkError: com.test.unit.Model.nativeMethod()

上篇文章《Android单元测试 - 如何开始?》讲述的"依赖隔离",这里要用到了!

改进单元测试:

public class ModelTest {      Model model;      @Before     public void setUp() throws Exception {         model = mock(Model.class);     }      @Test     public void testNativeMethod() throws Exception {         when(model.nativeMethod()).thenReturn(true);          Assert.assertTrue(model.nativeMethod());     } }

再run一下,pass了:

这里稍微讲讲java查找native方法的过程:

1).Model.java全名是com.test.unit.Model.java;

2).调用native方法nativeMethod()后, jvm会去找C++层com_test_unit_Model.cpp,再找com_test_unit_Model_nativeMethod()方法,并调用。

在APP运行过程,我们会把cpp编译成so文件,然后让APP加载到dalvik虚拟机。但在单元测试中,没有加载对应的so文件,也没有编译cpp呀!大牛们可能会尝试单元测试时加载so文件,但完全没有必要,也不符合单元测试的原则。

所以,我们可以直接用Mockito框架mock native方法就行啦。实际上,不仅仅是native方法需要mock,很多依赖的方法、类都要mock,下面会讲到更常用的场景。

(参考《Android JNI原理分析》)

3.解决内部new对象

小白:"我在Presenter里new Model,Model依赖比较多,会做sql操作,等等.....Presenter依赖Model返回结果,导致Presenter没法单元测试啦!求大神指点!"

小白C的例子:Model:

public class Model {     public boolean getBoolean() {         boolean bo = ....... // 一堆依赖,代码很复杂         return bo;     } }

Presenter:

public class Presenter {      Model model;      public Presenter() {         model = new Model();     }      public boolean getBoolean() {         return model.getBoolean());     } }

错误的单元测试:

public class PresenterTest {      Presenter presenter;      @Before     public void setUp() throws Exception {         presenter = new Presenter();     }      @Test     public void testGetBoolean() throws Exception {         Assert.assertTrue(presenter.getBoolean());     } }

还是那句话:依赖隔离。我们隔离Model依赖,即mock Model对象,而不是new Model()。

找找以上PresenterTest的问题吧:PresenterTest完全不知道Model的存在,意思是无法mock Model。那么,我们就想办法把mock Model传给Presenter——在Presenter构造函数传参!

改进Presenter:

public class Presenter {      Model model;      public Presenter(Model model) {         this.model = model;     }      public boolean getBoolean() {         return model.getBoolean();     } }

正确的单元测试:

public class PresenterTest {     Model     model;     Presenter presenter;      @Before     public void setUp() throws Exception {         model = mock(Model.class);// mock Model对象          presenter = new Presenter(model);     }      @Test     public void testGetBoolean() throws Exception {         when(model.getBoolean()).thenReturn(true);          Assert.assertTrue(presenter.getBoolean());     } }

事情就这么解决了。如果你觉得在Activity直接用默认Presenter构造函数,在构造函数new Model()比较方便,那就保留默认构造函数呗。当然使用dagger2就不存在多个构造函数了,都是构造传参。

4.静态方法

小白:"大神,我在Presenter用到静态方法...."笔者:"行了,知道你要说什么。"

Presenter:

public class Presenter {      public String getSignParams(int uid, String name, String token) {         return SignatureUtils.sign(uid, name, token);     } }

解决方法跟上面【解决内部new对象】大同小异,核心思想还是依赖隔离。

1).把sign(...)改成非静态方法;

2).把SignatureUtils作为成员变量;

3).构造方法传入SignatureUtils;

4).单元测试时,把mock SignatureUtils传给Presenter。

改进后Presenter:

public class Presenter {     SignatureUtils mSignUtils;      public Presenter(SignatureUtils signatureUtils) {         this.mSignUtils= signatureUtils;     }      public String getSignParams(int uid, String name, String token) {         return mSignUtils.sign(uid, name, token);     } }

5.RxJava异步转同步

小白:"大神..."

笔者:"为师掐指一算,料汝会遇此劫难。"

小白:(传说中从入门到出家?)

public class RxPresenter {      public void testRxJava(String msg) {         Observable.just(msg)                   .subscribeOn(Schedulers.io())                   .delay(1, TimeUnit.SECONDS) // 延时1秒 //                  .observeOn(AndroidSchedulers.mainThread())                   .subscribe(new Action1() {                       @Override                       public void call(String msg) {                           System.out.println(msg);                       }                   });     } }

单元测试

public class RxPresenterTest {      RxPresenter rxPresenter;      @Before     public void setUp() throws Exception {         rxPresenter = new RxPresenter();     }      @Test     public void testTestRxJava() throws Exception {         rxPresenter.testRxJava("test");     } }

运行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操作的类。

新建RxTools:

public class RxTools {     public static void asyncToSync() {         Func1 schedulerFunc = new Func1() {             @Override             public Scheduler call(Scheduler scheduler) {                 return Schedulers.immediate();             }         };          RxAndroidSchedulersHook rxAndroidSchedulersHook = new RxAndroidSchedulersHook() {             @Override             public Scheduler getMainThreadScheduler() {                 return Schedulers.immediate();             }         };          RxJavaHooks.reset();         RxJavaHooks.setOnIOScheduler(schedulerFunc);         RxJavaHooks.setOnComputationScheduler(schedulerFunc);          RxAndroidPlugins.getInstance().reset();         RxAndroidPlugins.getInstance().registerSchedulersHook(rxAndroidSchedulersHook);     } }

在RxPresenterTest.setUp()加一句RxTools.asyncToSync();:

public class RxPresenterTest {     RxPresenter rxPresenter;      @Before     public void setUp() throws Exception {         rxPresenter = new RxPresenter();          RxTools.asyncToSync();     }     ... }

再跑一次testTestRxJava():

总算输出"test",感谢上帝啊!(应该打赏下笔者吧^_^)

读者有没发现RxTools.asyncToSync()多加了一句RxJavaHooks.setOnComputationScheduler(schedulerFunc),意思将computation线程切换为immediate线程。笔者发现,仅仅添加RxJavaHooks.setOnIOScheduler(schedulerFunc),对于有delay的Obserable还是未通过,于是顺手把computation线程也切换了,于是就可以了。

还有RxJavaHooks.reset()和RxAndroidPlugins.getInstance().reset(),笔者发现,当运行大量单元测试时,有些会失败,但单独运行失败的单元测试,又通过了。百思不得其解后,添加了那两句.....可以了!

到此,相信大家对"Android单元测试中重要的问题有哪些"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

单元 测试 方法 运行 笔者 小白 线程 问题 函数 隔离 对象 文件 还是 切换 重要 大神 类名 静态 编译 输出 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技有限公司 互联网加科技 深圳市人人互联网科技有限公司 互联网是第几次科技革命的成果 中国互联网科技工作委员会毛军 互联网科技有限公司图片 新浪科技互联网 上游互联网科技 互联网科技的未来发展 顺网科技2021年互联网排名 天速互联网络科技有限公司 广州优美互联网科技 互联网教育科技公司vipkid 移动互联网科技股 乌鲁木齐新华智原互联网科技学校 互联网科技快讯热点 广东鹅鹅鹅互联网科技有限公司 中国互联网公司的科技投入 重庆科技产业互联网有哪些 互联网大会出现的黑科技 河南云网互联网络科技有限公司 为想互联网科技怎么样 中国互联网科技工作委员会毛军 奇士达互联网科技 互联网女皇 腾讯科技 隆华科技工业互联网 如何创新互联网科技 互联网在线教育科技创业 互联网的科技体现在哪里 亚光科技低轨卫星互联网
0