Android 自动化测试之——Instrumentation

前沿:
单元测试junit3,junit4等属于本地测试,无需链接android 模拟器或者真机。Instrumentation 不同于junit3,junit4需要至少连接一种外设(真机或者模拟器)

概要
Android 测试环境的核心是一个Instrumentation框架,在这个框架下,你的测试应用程序可以精确控制应用程序。使用Instrumentation, 你可以在主程序启动之前,创建模拟的系统对象,如Context;控制应用程序的多个生命周期;发送UI事件给应用程序;在执行期间检查程序状态。 Instrumentation框架通过将主程序和测试程序运行在同一个进程来实现这些功能。

Android 自动化测试之——Instrumentation_第1张图片

一、什么是Instrumentation

 Android自身提供了对instrumentation测试的基本支持,先来看下测试框架的继承树,已经集成在android sdk中

Android 自动化测试之——Instrumentation_第2张图片

可以看到主要有AndroidTestCase和InstrumentationTestCase。Instrumentation和Activity有点类似,只不过Activity是需要一个界面的,而Instrumentation并不是这样的,我们可以将它理解为一种没有图形界面的,具有启动能力的,用于监控其他类(用Target Package声明)的工具类。

二、Instrumentation可以做什么

Instrumentation可以模拟ui交互,进行回归测试。

"true" | "false"]
                 android:handleProfiling=["true" | "false"]
                 android:icon="drawable resource"
                 android:label="string resource"
                 android:name="string"
                 android:targetPackage="string" />

想要使用instrumentation 功能需要在清单文件中进行声明,并指定监控的包名或者具体的类。 这是在Eclipse中但是在android studio 中发现不需要再清单文件中进行声明。

下面通过下面的Demo简单介绍一下 Instrumentation的使用,模拟点击事件,对ui显示结果进行判断

package com.czt.saisam.unittest.android;

import android.content.Intent;
import android.os.SystemClock;
import android.test.InstrumentationTestCase;
import android.widget.Button;
import android.widget.TextView;

import com.czt.saisam.unittest.MainActivity;
import com.czt.saisam.unittest.R;

/**
 * 2016/12/26
 * 早期的还需要 test开头才能识别
 * junit 4  则可以使用注解
 */

public class InstTestCase extends InstrumentationTestCase {

    MainActivity mActivity = null;

    private Button button = null;

    private TextView text = null;

    @Override
    protected void tearDown() throws Exception {
        // TODO Auto-generated method stub  
        mActivity.finish();

        super.tearDown();
    }

    @Override
    protected void setUp() throws Exception {
        // TODO Auto-generated method stub  
        super.setUp();
        Intent intent = new Intent();

        intent.setClassName("com.czt.saisam.unittest", MainActivity.class.getName());

        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        mActivity = (MainActivity) getInstrumentation().startActivitySync(intent);

        text = (TextView) mActivity.findViewById(R.id.text1);

        button = (Button) mActivity.findViewById(R.id.id_btn_fun);

    }  

    /* 
     *  
     * 活动功能测试 
     */

    public void testActivity() throws Exception {
        // 测试键壮性,连续运行某项功能100次,点击Button 100次  
        for (int i = 0; i < 100; ++i) {
            getInstrumentation().runOnMainSync(new PerformClick(button));
            SystemClock.sleep(10); // 中间间隔 0.5秒
        }
        assertEquals("SM-G9250G9250ZCU2DPJ2", text.getText().toString()); //检查运行后的输出结果
    }
    /*
     *  
     * 模拟按钮点击的接口 
     */

    private class PerformClick implements Runnable {
        Button btn;

        public PerformClick(Button button) {
            btn = button;
        }

        public void run() {
            btn.performClick();
        }

    }

}  

主Activity


package nuoyuan.com.myapplication;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        tv = (TextView) this.findViewById(R.id.text1);
        this.findViewById(R.id.id_btn_fun).setOnClickListener(mOnClickListener);

    }


    View.OnClickListener mOnClickListener = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.id_btn_fun:
                    fun();
                    break;
                default:

            }
        }
    };

    private void fun() {
        tv.setText(android.os.Build.MODEL + android.os.Build.getRadioVersion());
    }
}

运行结果

Android 自动化测试之——Instrumentation_第3张图片

模拟点击

Android 自动化测试之——Instrumentation_第4张图片

这样做压力测试是不是很爽。

当然InstrumentationTestCase 的功能不止这些,一些扩展功能甚至可以模拟用户和ui进行交互。从而解放双手。 下面会分篇进行介绍衍生类的使用

三、Instrumentation同类工具介绍(monkey自动化测试,espross测试,UiAutomator)

这里只是简单介绍常用的几种自动化测试,主要以google support lib 为基础。

1、Monkey是Android SDK自带的测试工具,在测试过程中会向系统发送伪随机的用户事件流,如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行压力测试,也有日志输出。实际上该工具只能做程序做一些压力测试,由于测试事件和数据都是随机的,不能自定义,所以有很大的局限性。

2、MonkeyRunner也是Android SDK提供的测试工具。严格意义上来说MonkeyRunner其实是一个Api工具包,比Monkey强大,可以编写测试脚本来自定义数据、事件。缺点是脚本用Python来写,对测试人员来说要求较高,有比较大的学习成本。

3、Instrumentation是早期Google提供的Android自动化测试工具类,虽然在那时候JUnit也可以对Android进行测试,但是Instrumentation允许你对应用程序做更为复杂的测试,甚至是框架层面的。通过Instrumentation你可以模拟按键按下、抬起、屏幕点击、滚动等事件。Instrumentation是通过将主程序和测试程序运行在同一个进程来实现这些功能,你可以把Instrumentation看成一个类似Activity或者Service并且不带界面的组件,在程序运行期间监控你的主程序。缺点是对测试人员来说编写代码能力要求较高,需要对Android相关知识有一定了解,还需要配置AndroidManifest.xml文件,不能跨多个App。

4、UiAutomator也是Android提供的自动化测试框架,基本上支持所有的Android事件操作,对比Instrumentation它不需要测试人员了解代码实现细节(可以用UiAutomatorviewer抓去App页面上的控件属性而不看源码)。基于Java,测试代码结构简单、编写容易、学习成本,一次编译,所有设备或模拟器都能运行测试,能跨App(比如:很多App有选择相册、打开相机拍照,这就是跨App测试)。缺点是只支持SDK 16(Android 4.1)及以上,不支持Hybird App、WebApp。

5、Espresso是Google的开源自动化测试框架。相对于Robotium和UIAutomator,它的特点是规模更小、更简洁,API更加精确,编写测试代码简单,容易快速上手。因为是基于Instrumentation的,所以不能跨App。(后面会着重介绍Espresso框架)

引用链接:

官方介绍:
https://stuff.mit.edu/afs/sipb/project/android/docs/guide/topics/manifest/instrumentation-element.html
Android 和 ios 自动化框架简介 https://www.zhihu.com/question/19716849
Android 清单文件详解
Instrumenttation http://blog.csdn.net/think_soft/article/details/7563525

常用的自动化测试工具
https://www.zhihu.com/question/19716849/answer/42525356

Instrumentation 总结 http://blog.csdn.net/apaking/article/details/19083913

同时对以上链接作者表示感谢

下载demo 链接 https://github.com/yatou252303/android-testing

你可能感兴趣的:(android,单元测试,自动化脚本测试,自动化测试)