通过Espresso测试异步代码

原创 2018年04月16日 14:01:05

本篇讲如何通过Espresso实现异步测试.

概述

如果没有框架的支持测试异步代码还是非常具有挑战性的 ! 在 Espresso 之前典型的做法就是等待预定的时间.或者在测试代码使用 CountDownLatch 类的实例, 并在异步处理完成时发出信号. 而 Espresso 使得异步测试变得容易很多,因为它自动检测 AsynchronousTask 后面的线程池.它还监视用户界面的事件队列, 仅在没有任务运行时才继续进行测试.

示例

下面示例根据官方的异步测试案例进行了简化处理:

Espresso 提供了 IdlingResource 接口用来检视当前资源是否空闲.我们可以根据这个接口进行简单的封装让其更适合我们使用.

在开始下面内容之前需要检查一下你的 Gradle 文件是否添加了 implementation ‘com.android.support.test.espresso:espresso-intents:3.0.1’ 依赖, 这个依赖是供 src/main/java 目录下访问的,用于我们接下来封装异步测试的工具类.

src/main/java 目录下创建 SimpleCountingIdlingResource 类,实现 IdlingResource 接口. 该类实现整个项目异步请求个数的检视.

package com.lulu.androidtestdemo.espresso.utils;

import android.support.test.espresso.IdlingResource;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * Created by zhanglulu on 2018/3/8.
 */
public class SimpleCountingIdlingResource implements IdlingResource {

    private final String mResourceName;

    //这个counter值就像一个标记,默认为0
    private final AtomicInteger counter = new AtomicInteger(0);

    private volatile ResourceCallback resourceCallback;

    public SimpleCountingIdlingResource(String resourceName) {
        mResourceName = resourceName;
    }

    @Override
    public String getName() {
        return mResourceName;
    }

    @Override
    public boolean isIdleNow() {
        return counter.get() == 0;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        this.resourceCallback = resourceCallback;
    }

    //每当我们开始异步请求,把counter值+1
    public void increment() {
        counter.getAndIncrement();
    }

    //当我们获取到网络数据后,counter值-1;
    public void decrement() {
        int counterVal = counter.decrementAndGet();
        //如果这时counter == 0,说明异步结束,执行回调。
        if (counterVal == 0) {
            //
            if (null != resourceCallback) {
                resourceCallback.onTransitionToIdle();
            }
        }
        if (counterVal < 0) {
            //如果小于0,抛出异常
            throw new IllegalArgumentException("Counter has been corrupted!");
        }
    }
}

在同一目录下添加 EspressoIdlingResource 类, 作为 SimpleCountingIdlingResource 的管理类,负责该类的创建和管理.

public class EspressoIdlingResource {
    private static final String RESOURCE = "GLOBAL";

    private static SimpleCountingIdlingResource mCountingIdlingResource =
            new SimpleCountingIdlingResource(RESOURCE);

    public static void increment() {
        mCountingIdlingResource.increment();
    }

    public static void decrement() {
        mCountingIdlingResource.decrement();
    }

    public static IdlingResource getIdlingResource() {
        return mCountingIdlingResource;
    }
}

现在在我们的待测试的 Activity 中只需在异步代码开始时添加 EspressoIdlingResource.increment(), 结束时添加 EspressoIdlingResource.decrement() , 并添加 getIdlingResource() 方法方便我们在测试方法中调用.(可能这样做对代码有耦合,但是官方的做法确实如此).如果是在真正的项目中, 可以考虑将其放在BaseActivity中,下面就是待测试的 Activity.

public class TestActivity extends AppCompatActivity {

    private TextView text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        text = findViewById(R.id.text);
    }

    public void onButtonClick(View view) {
        EspressoIdlingResource.increment();
        Toast.makeText(this, "View Clicked", Toast.LENGTH_SHORT).show();
        switch (view.getId()) {
            case R.id.my_view:
                new Thread(() -> {
                    try {
                        Thread.sleep(2000);
                        mHandler.sendEmptyMessage(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }).start();
                break;
            case R.id.my_view2:
                text.setText("Running");
                break;
        }

    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            text.setText("Done");
            if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {
                EspressoIdlingResource.decrement();
            }
        }
    };

    @VisibleForTesting
    public IdlingResource getIdlingResource() {
        return EspressoIdlingResource.getIdlingResource();
    }
}

下面就是对应的测试方法, 检查 R.id.text 代码将会在子线程执行完成之后进行验证.

/**
 * Created by zhanglulu on 2018/3/8.
 */
@RunWith(AndroidJUnit4.class)
public class EspressoAsyncTest {
    private IdlingResource idlingresource;

    @Rule
    public ActivityTestRule<TestActivity> activityRule = new ActivityTestRule(TestActivity.class);

    @Before
    public void before() {
        //调用Activity中我们已经设置好的getIdlingresource()方法,获取Idlingresource对象
        idlingresource = activityRule.getActivity().getIdlingResource();
        IdlingRegistry.getInstance().register(idlingresource);
    }
    @After
    public void after() {
        IdlingRegistry.getInstance().unregister(idlingresource);
    }
    @Test //is(String.class), is("Done")
    public void testAsync() {
        onView(withId(R.id.my_view)).perform(click());
        onView(withId(R.id.text)).check(matches(withText("Done")));
    }
}

敲行代码再睡觉

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013144863/article/details/79959757

测试

cshi
  • 2017年06月19日 09:12

Android 自动化测试 Espresso篇:异步代码测试

前言在我的上一篇文章 通关Android 单元测试(一)Espresso篇:简介&基础使用 中,简单阐述了Espresso的基本使用,以及为什么我们要使用Espresso。实际上,Espresso进行...
  • mq2553299
  • mq2553299
  • 2017-07-05 19:39:29
  • 1688

Espresso——Android测试工具Espresso简介

本文通过网络文章来介绍Espresso的使用 Espresso是一个新工具,相对于其他工具,API更加精确。并且规模更小、更简洁并且容易学习。它最初是2013年GTAC大会上推出的,目标...
  • shandong_chu
  • shandong_chu
  • 2015-07-24 16:33:43
  • 3097

Android Espresso单元测试

Espresso介绍在Android单元测试中,谷歌官方推荐使用Espresso框架,根据谷歌官方介绍,Espresso的最关键的优势就是它能自动同步模拟行为对UI的测试,它能够检测到主线程空闲状态的...
  • xuguoli_beyondboy
  • xuguoli_beyondboy
  • 2016-01-07 15:17:59
  • 3990

使用Record Espresso Test功能自动生成测试代码

上一篇文章介绍了如何使用Espresso框架编写自动化测试代码,算是一篇Espresso的入门文章吧,如果还不知道Espresso如何编写测试代码的,建议看一下上一篇文章,毕竟这篇文章是以上一篇文章为...
  • qiang_xi
  • qiang_xi
  • 2016-10-30 00:06:14
  • 2392

Espresso 不依赖源代码的测试

之前一段时间通过同步更新开发的代码进行Espresso的测试,发现经常因为build.gradle的更新,进行会出现一些冲突的问题,当然也是个人能力的问题,总觉得经常花费时间在解决这些问题上有些不值当...
  • qq744746842
  • qq744746842
  • 2016-09-17 23:07:02
  • 968

Google I/O 2016 笔记之Espresso 进阶

Google I/O 2016 笔记之Espresso 进阶
  • u014608640
  • u014608640
  • 2016-09-14 10:09:41
  • 757

Android 自动化测试 Espresso篇:简介&基础使用

前言最近在尝试深入学习Android单元测试。以前笔者对于单元测试的理解很简单,做一个简单的API测试获取Server端数据,或者测试对应简单的工具类和数据处理的逻辑。经过这近一个月的碎片化学习,深深...
  • mq2553299
  • mq2553299
  • 2017-07-01 16:24:57
  • 1590

Android自动化测试框架Espresso(四)——intent测试

Android自动化测试框架Espresso的intent测试
  • yjp19871013
  • yjp19871013
  • 2017-05-10 21:25:39
  • 935

Android UI测试之Espresso使用

暑假实习的单位,被分到了一个测试组,因为我是搞android开发的,所以被分到了自动化测试小组,所以了解了一些UI自动化测试。主要就是看了下官方文档关于UI自动haul测试的介绍以及一些框架,比如Ap...
  • qq_19431333
  • qq_19431333
  • 2017-09-12 10:08:13
  • 666
收藏助手
不良信息举报
您举报文章:通过Espresso测试异步代码
举报原因:
原因补充:

(最多只允许输入30个字)