`
xuanzhui
  • 浏览: 200918 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Android异步函数单元测试

阅读更多

大部分内容也适合Java,此处主要是对sdk类别的module做unit test,不涉及UI

 

1. 配置

1) 对于涉及到android原生的类库返回默认的对象,否则,之后遇到Log之类的语句都需要手动mock,但是不要期待这个配置对android API提供全面的支持

 

testOptions {
    unitTests.returnDefaultValues = true
}

 参考这边的说明 Unit testing support

"Method ... not mocked."

The android.jar file that is used to run unit tests does not contain any actual code - that is provided by the Android system image on real devices. Instead, all methods throw exceptions (by default). This is to make sure your unit tests only test your code and do not depend on any particular behaviour of the Android platform (that you have not explicitly mocked e.g. using Mockito). If that proves problematic, you can add the snippet below to your build.gradle to change this behavior:

android {
  // ...
  testOptions { 
    unitTests.returnDefaultValues = true
  }
}
We are aware that the default behavior is problematic when using classes like Log or TextUtils and will evaluate possible solutions in future releases.

 

2) 配置依赖库

testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:1.10.+"
testCompile ('org.powermock:powermock-api-mockito:1.6.3') {
    exclude module: 'hamcrest-core'
    exclude module: 'objenesis'
}
testCompile ('org.powermock:powermock-module-junit4:1.6.3') {
    exclude module: 'hamcrest-core'
    exclude module: 'objenesis'
}

 其中powermock用于对static和final方法提供mock支持

mockito site

powermock site

 

另外也有人对powermock提出了质疑,大致的理由是,为了实现对static和final方法的mock,powermock在jvm中对被测试类的字节码进行了部分修改(只是在测试运行时进行了修改,并不会影响你的源码),所以实际测试的类和你自己写的是有部分区别的,而且,进一步就引发了对static用法的质疑,参见:

PowerMock + Mockito VS Mockito alone

Why is wide usage of PowerMock problematic

 

3) 设置Android Studio

左边栏Build Variants -> Test Artifact 选择 Unit Tests

 

2. 对于单进程的异步请求单元测试

首先有如下的类

 

public class JustAClass {
    //callback接口
    public interface JustACallBack {
        void callFunc(JustAResult result);
    }

    //callback中携带的数据父接口
    public interface JustAResult {}

    //用于测试的数据类
    public class ImplementedResult implements JustAResult{
        public ImplementedResult(String content) {this.content = content;}
        public String content;
    }

    //此处的测试函数
    public void mainThreadFunc(final JustACallBack callBack) {
        callBack.callFunc(new ImplementedResult("can you reach me"));
    }
}

 Mockito提供了ArgumentCaptor用于获取异步回调的结果

public class JustAClassTest {

    @Captor
    ArgumentCaptor<JustAClass.JustAResult> captor;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testMainThreadFunc() throws Exception {

        JustAClass justAClass = new JustAClass();

        JustAClass.JustACallBack callBack = Mockito.mock(JustAClass.JustACallBack.class);

        justAClass.mainThreadFunc(callBack);

        Mockito.verify(callBack).callFunc(captor.capture());

        Assert.assertEquals(((JustAClass.ImplementedResult) captor.getValue()).content, "can you reach me");
    }
}

 

3. 如果被测试函数启动了一个子线程,然后在子线程中调用回调接口,那么上面的测试是无效的

一般mockito会报错 Wanted but not invoked,出错点在

Mockito.verify(callBack).callFunc(captor.capture());

原因是子线程尚未结束,而主进程已经开始去校验结果了。

首先被测试的类

public class JustAClass {
    //callback接口
    public interface JustACallBack {
        void callFunc(JustAResult result);
    }

    //callback中携带的数据父接口
    public interface JustAResult {}

    //用于测试的数据类
    public class ImplementedResult implements JustAResult{
        public ImplementedResult(String content) {this.content = content;}
        public String content;
    }

    //此处的测试函数
    public void mainThreadFunc(final JustACallBack callBack) {
        callBack.callFunc(new ImplementedResult("can you reach me"));
    }

    //此处的测试函数
    public void subThreadFunc(final JustACallBack callBack) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //模拟耗时操作0.5s
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                callBack.callFunc(new ImplementedResult("can you reach me"));
            }
        }).start();
    }
}

 此时可以通过加锁的方式来等待子线程结束,这边用的CountDownLatch

CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset.

 

public class JustAClassTest {

    @Captor
    ArgumentCaptor<JustAClass.JustAResult> captor;
    CountDownLatch latch;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        //for child thread async
        latch = new CountDownLatch(1);
    }

    @Test
    public void testMainThreadFunc() throws Exception {

        JustAClass justAClass = new JustAClass();

        JustAClass.JustACallBack callBack = Mockito.mock(JustAClass.JustACallBack.class);

        justAClass.mainThreadFunc(callBack);

        Mockito.verify(callBack).callFunc(captor.capture());

        Assert.assertEquals(((JustAClass.ImplementedResult) captor.getValue()).content, "can you reach me");
    }

    @Test
    public void testSubThreadFunc() throws Exception {
        JustAClass justAClass = new JustAClass();

        justAClass.subThreadFunc(new JustAClass.JustACallBack() {
            @Override
            public void callFunc(JustAClass.JustAResult result) {
                Assert.assertTrue(result instanceof JustAClass.ImplementedResult);

                JustAClass.ImplementedResult resultReal = (JustAClass.ImplementedResult) result;

                Assert.assertEquals("can you reach me", resultReal.content);

                latch.countDown();
            }
        });

        //wait 1s maximum before callback returns
        latch.await(1000, TimeUnit.MILLISECONDS);
    }
}

 

分享到:
评论

相关推荐

    android单元测试实例一

    在Android开发中,单元测试是确保代码质量的重要环节。它允许开发者验证单个代码模块(如函数或类)的功能是否按预期工作。本实例聚焦于Android应用中的单元测试,特别是针对登录界面及其相关功能的测试。我们将探讨...

    Android单元测试源码.zip

    "Android单元测试源码.zip"可能包含了一个或多个Android项目的单元测试代码示例,这些示例展示了如何在Android环境中有效地编写和执行单元测试。 在Android中,我们通常使用JUnit作为基础测试框架,配合Mockito进行...

    Android JUnit单元测试实例

    在Android开发中,单元测试是确保代码质量、可维护性和稳定性的重要工具。JUnit是一个流行的Java测试框架,而在Android环境中,我们可以使用Android JUnit进行单元测试。这篇内容将深入探讨Android JUnit单元测试的...

    android单元测试

    单元测试是指针对软件中的最小可测试单元进行检查和验证,对于Android应用来说,这通常是单个函数或类。通过编写自动化测试用例,我们可以确保这些单元在各种条件下都能按预期工作,从而发现并修复潜在的错误。 ...

    Android应用源码之测试反应能力源码.zip

    1. JUnit:基础的单元测试框架,可以用于测试应用程序中的各个函数和类。 2. Espresso:用于UI测试,它可以直接与运行的应用进行交互,检查UI组件的状态和行为,验证它们的响应时间。 3. Robolectric:一个Android...

    android-architecture-sample,使用kotlin、coroutines、架构组件等的示例应用程序。进行单元测试和仪器测试。.zip

    4. **单元测试和仪器测试**:项目的测试部分是软件质量保证的关键。通过单元测试,可以对单个功能或组件进行验证,确保其正确性。而仪器测试则是在模拟真实设备环境下进行,更接近实际运行情况。这个示例包含了这两...

    android-junit5,使用junit 5进行android测试。.zip

    JUnit5为Android开发者带来了更强大、更灵活的测试能力,无论是基本的单元测试还是复杂的场景模拟,都能更好地满足需求。通过合理利用其新特性,可以提升测试的质量和效率,从而提高软件的可靠性。在实际项目中,...

    dagger2Example:带有 Dagger2、Espresso 2.0 和 mockito 的 Android 单元测试示例

    "带有 Dagger2、Espresso 2.0 和 mockito 的 Android 单元测试示例"说明了这个项目不仅涉及到Dagger2,还包含了 Espresso 2.0(用于UI测试)和 Mockito(用于模拟对象的单元测试框架)。因此,这个项目是一个综合性...

    androidTest

    单元测试针对的是应用程序的最小可测试单元,如单个函数或方法,而仪器测试则是在真实设备或模拟器上运行,对整个应用程序或者组件进行的测试,包括UI交互和系统集成。 **单元测试**: 在Android Studio中,单元...

    Android Test

    Android Test是Android平台提供的一套全面的测试框架和工具集合,它允许开发者对应用程序进行不同层次的测试,包括单元测试、功能测试、性能测试和UI测试等。下面我们将深入探讨Android Test的各个方面。 一、JUnit...

    Android-KotlinAndroid脚手架项目

    9. **单元测试和UI测试**:使用JUnit、Espresso等工具编写测试用例,确保代码的质量和稳定性。 10. **代码规范和Linter**:通过Gradle插件,如Ktlint,来检查代码风格和潜在问题,保持代码整洁。 这个"Kotlin ...

    Android_test:Android测试示例

    1. **单元测试**:这是最基础的测试,主要针对应用中的单个函数或组件进行,确保它们在独立运行时能正确工作。Java的JUnit框架是进行单元测试的常用工具,开发者可以使用`@Test`注解来定义测试方法,并使用`...

    Android开发三剑客源代码

    单元测试是确保代码质量的重要手段,它针对代码的最小可测试单元进行验证,比如函数或方法。在Android开发中,我们可以使用JUnit、Mockito等工具进行单元测试。源代码中可能包含了大量的测试用例,展示如何为Android...

    Android开发教程基础版 Android中文开发教程

    Android Studio内置了丰富的测试工具,包括单元测试、UI测试、性能测试等。学会编写测试用例和调试技巧,能有效提高代码质量。 以上只是《Android开发教程基础版》的部分核心知识点,通过深入学习并实践这些内容,...

    Android小项目集合100多个

    12. **Android测试**:包括单元测试、UI测试、Espresso、JUnit和Mockito等工具,它们可以帮助开发者确保代码的质量和应用的稳定性。 13. **Material Design**:谷歌推出的Material Design设计语言为Android应用设定...

    《用Kotlin做Android开发》PDF

    6. 测试与调试:涵盖单元测试、集成测试以及 Espresso UI 测试,介绍如何在Kotlin中编写测试代码,以及如何使用Android Studio的调试工具进行问题排查。 7. 发布与维护:讲解如何配置Gradle构建系统,进行版本控制...

    Packt.Android.Application.Testing.Guide.Incl.Code

    这本书全面覆盖了Android测试的各个方面,从基本的单元测试到复杂的UI自动化测试,包括代码覆盖率分析和性能测试。 在Android开发过程中,测试是确保软件质量的关键环节。本书首先讲解了测试的重要性,阐述了为什么...

    android-testing.zip

    1. **JUnit**:作为Java世界中最常用的单元测试框架,JUnit在Android测试中同样扮演着关键角色。"testing-samples-master"中可能有一个JUnit的示例,展示了如何编写和运行针对Android组件(如Activity、Service)的...

Global site tag (gtag.js) - Google Analytics