行为触发之Android自动化测试instrumentation(一)

由于对测试并没有太多的概念,一不小心搜索到各种前缀:Instrumentation、InstrumentationTestCase、InstrumentationTestSuite、InstrumentationTestRunner 傻了眼,但仔细一看把前缀去掉后大致就分类为了这三类:TestCase、TestSuite、TestRunner。用中文来翻译应该可以认为是测试样例,测试集合,测试运行工具吧。之后再官方文档中搜索InstrumentationTestRunner,用法介绍http://developer.android.com/reference/android/test/InstrumentationTestRunner.html
常规Android自动化方法分3步走:
1、先继承各种****TestCase完成测试样例的编写(这里有很多***TestCase,适用于不用场景,都可以使用,对于broadcastreceiver用intent可以触发)
2、在Andriodmanifest中需要加入<instrumentation> 并配置些啥
3、完成之后可以adb shell am instrument ****执行我们的自动化测试

下面用一个小demo来完成入门,主要还是自己单独建立一个测试项目,但重做安全的角度来说,我们更多的是在做黑盒测试,那么就会产生了不少疑问,在下面阐述。
1.先是需要测试的app,我这里简单写了一个

[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.example.hello;  

import com.example.hello.R;  

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;  

public class HelloActivity extends Activity {  

    final String TAG = "helloactivity";
    Button mButton;
    EditText mEditText;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "hello onCreate");
        setContentView(R.layout.activity_hello_test);
        mButton = (Button) findViewById(R.id.Button1);
        mEditText = (EditText) findViewById(R.id.EditText1);
        mEditText.setHint("INPUT");
        mButton.setOnClickListener(new OnClickListener(){
            public void onClick(View v){
                String msg = mEditText.getText().toString();
                if (msg.equals("1")) {
                    Toast.makeText(getApplicationContext(), "hello_1", Toast.LENGTH_LONG).show();
                } else if(msg.equals("2")){
                    Toast.makeText(getApplicationContext(), "hello_2", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(getApplicationContext(), "hello_nothing", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }  

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.hello_test, menu);
        return true;
    }  

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG,"hello onDestroy");
    }  

功能就是输入1、2、其他字符串之后onClick之后会走不同路径

2、编写自动化测试的TestCase
官方推荐测试样例项目建立路径最好满足一下规范(刚开始以为这样子是为了更好的找到测试APP中相应的类,后来想想也不对,不是同一个项目,为啥能直接导入测试APP的类import com.example.hello.HelloActivity呢,自己还索性在其他路径建了一个测试项目,发现com.example.hello.HelloActivity确实能导入,而其他项目的类则不行,后来想想应该是target的原因,ADT检测该项目没有该类,便自动以target为目标匹配吧):
MyProject/
      AndroidManifest.xml
      res/
          ... (resources for main application)
      src/
          ... (source code for main application) ...
      tests/
          AndroidManifest.xml
          res/
              ... (resources for tests)
          src/
              ... (source code for tests)

上图新建-》其他项目-》Android Test Project:

之后可以选择需要测试的目标APP:

我们这里需要测试的是Hello,这样自动生成后,ADT自动帮我们完成了第二步中在AndroiManifest里加入需要声明的东西
[html] view plain copy 在CODE上查看代码片派生到我的代码片
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.hello.test"
    android:versionCode="1"
    android:versionName="1.0" >  

    <uses-sdk android:minSdkVersion="8" />  

    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.example.hello"
        android:label="the hello test" />  

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <uses-library android:name="android.test.runner" />
    </application>  

</manifest>  

target指明了需要测试的目标,label为测试的标签(在模拟器中使用dev tool可以看到对应的标签),这里写了个一个简单的测试样例,自动向编辑框中输入1,2,3然后分别自动点击按钮
[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.example.hello.test;  

import android.app.Instrumentation;
import android.content.Intent;
import android.os.SystemClock;
import android.test.InstrumentationTestCase;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;  

import com.example.hello.HelloActivity;
import com.example.hello.R;  

public class TestHelloActiviry extends InstrumentationTestCase {  

    final String TAG = "TestHelloAppTestHelloApp";   

    Button mHelloTestButton;
    EditText mHelloEditText;
    HelloActivity mHelloTestActivity;
    Instrumentation mInstrumentation;  

    public void testHelloActivity() {
        Log.i(TAG, "call testHelloActivity()");
        mHelloTestButton = (Button)mHelloTestActivity.findViewById(R.id.Button1);
        mHelloEditText = (EditText)mHelloTestActivity.findViewById(R.id.EditText1);
        for (int i = 0; i < 3; i++) {
            //设置事件在主线程中执行
            mInstrumentation.runOnMainSync(new Click(mHelloTestButton,mHelloEditText,Integer.toString(i)));
            SystemClock.sleep(3000);
        }  

    }  

    public void testHelloActivity2() {  

    }  

    private class Click implements Runnable{
        Button button;
        EditText editText;
        String str;
        Click(Button b,EditText e,String s){
            button = b;
            editText = e;
            str = s;
        }
        @Override
        public void run() {
            editText.setText(str);
            button.performClick();  

        }
    }  

    //负责testcase开始前的初始化工作
    @Override
    protected void setUp() throws Exception {
        super.setUp();
        Log.i(TAG, "call setUp()");
        mInstrumentation = getInstrumentation();
        Intent intent = new Intent();
        intent.setClassName("com.example.hello", "com.example.hello.HelloActivity");
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //通过intent触发activity
        mHelloTestActivity = (HelloActivity)mInstrumentation.startActivitySync(intent);
    }  

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();  

        Log.i(TAG, "tearDown()");
    }  

}  

3、运行起来吧
接下来要么直接在ADT中run as-》Android jUnit test,但这样太智能了,我们并不知道实际上做了什么,对于我们安全来说,我们肯定不能开个ADT直接点点点吧。索性跟踪了一下console发现如下:
[html] view plain copy 在CODE上查看代码片派生到我的代码片
trouble writing output: already prepared
[2014-03-15 18:40:42 - tests] ------------------------------
[2014-03-15 18:40:42 - tests] Android Launch!
[2014-03-15 18:40:42 - tests] adb is running normally.
[2014-03-15 18:40:42 - tests] Performing android.test.InstrumentationTestRunner JUnit launch
[2014-03-15 18:40:42 - tests] Automatic Target Mode: using device ‘?‘
[2014-03-15 18:40:42 - tests] Uploading tests.apk onto device ‘?‘
[2014-03-15 18:40:42 - tests] Installing tests.apk...
[2014-03-15 18:41:09 - tests] Success!
[2014-03-15 18:41:09 - tests] Project dependency found, installing: Hello
[2014-03-15 18:41:14 - Hello] Uploading Hello.apk onto device ‘?‘
[2014-03-15 18:41:14 - Hello] Installing Hello.apk...
[2014-03-15 18:41:41 - Hello] Success!
[2014-03-15 18:41:41 - tests] Launching instrumentation android.test.InstrumentationTestRunner on ?
[2014-03-15 18:41:43 - tests] Sending test information to Eclipse  

其实是在安装tests.apk时候,ADT根据target检测到依赖关系,接着自动安装了Hello.apk。接着运行instrumentation,也就是之前提到的命令
[java] view plain copy 在CODE上查看代码片派生到我的代码片
am instrument -w com.example.hello.test/android.test.InstrumentationRunner  

然后这条am是不需要ROOT权限的,具体命令深入研究的话查看相关文档,你懂得我懂得。暂时还没测试但是据一些资料查阅,需要被测试与测试样例有同一签名才能进行测试,这或许也是需要重打包的另一个因素。

顺便补充一条命令:
[html] view plain copy 在CODE上查看代码片派生到我的代码片
pm list instrumentation
可以查看手机目前装了那些instrumentation

4.回到正题
前面介绍了那么多,其实只是为了搞安全行为触发做铺垫,为了解决之前开篇的论文疑惑做铺垫。假设我们接触不到源码,假设我们也需要脚本自动化完成触发,那这时候不肯能在ADT ADT的叫叫叫了!
走到这里,有没有发现其实重打包可能是为了被测试APP,测试样例APP有同一个签名。同时为了提示数据被传输,需要Toast,或许重打包另一些原因就在于这吧,数据触发的时候把相应的事件打印出来(因为测试样例的APP是不能弹出来的,最多log),所以论文里的重打包或许只是在做这些。或者就是他们采用的方法不一样,是把测试样例smali放入被测试smali文件夹,修改打印内容下并修改AndroidManifest(有的测试写在单独程序java包中,而不是单独一个测试工程)
通过一些自动化逆向工具,分析被测试APP自然能看到一些有用的信息,通过AndroidManifest可以看到组件、intent。或许我们还需要view控件,那么我们可以通过解析出来的文件查看,最后保证签名一样就可以更为完整测试了:

layout->activity_main可以看到控件信息主要是id,通过values的public我们可以找到对应id的数值,那么这时候就不存在R.id.xxxxx了,填入解析出来的数字就好了
[java] view plain copy 在CODE上查看代码片派生到我的代码片
mHelloTestButton = (Button)mHelloTestActivity.findViewById(xxxxx);
mHelloEditText = (EditText)mHelloTestActivity.findViewById(xxxxx);
逆向看了一下,暂时没有什么特别的地方,要有问题也就是能不能找到target对应的import 类了,毕竟有时候需要里面的内容,暂时只思考到了这里,还有很多API是很有用的,期待下次继续吧!
时间: 2024-10-08 02:09:03

行为触发之Android自动化测试instrumentation(一)的相关文章

Instrumentation类——Android自动化测试学习历程

这里需要把Instrumentation类的视频的上.中.下三集一起看,把内容总结一下... 视频地址: http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=881433&courseId=712011 http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=878104&

Android自动化测试工具实现简述

前言 自动化测试在产品开发和测试中都有着非常重要的作用.在产品开发阶段,可靠又重复性地运行以确保没有引进回归问题:在产品测试阶段,可以节省人力成本和时间成本,并能保证更大范围的覆盖.Android自动化测试工具同样可以节省不少人力和时间成本,对其研究和实现对于提高测试效率具有一定的意义.目前市面上也有不少Android自动化测试工具,本人在现有工具的基础上,加上自己的理解和实践向大家介绍自动化测试工具的原理和实现. 了解自动化测试的一定对Robotium并不陌生,Robotium是一款国外的An

Android 自动化测试框架

Android常用的自动化测试工具框架: Monkey,MonkeyRunner,UIAutomator,Robotium,Appium,Monkey Talk 但是这些工具框架都有什么关系呢,先通过一张图来了解一下吧.(图是某博客上借过来的) 是不是一脸懵逼,不知道这是什么鬼.下面详细了解一下. 一.Monkey 是Android SDK自带的测试工具,是一个命令行工具,可以运行在模拟器中或者实际设备中,它向系统发送伪随机的用户事件流(如按键输入,触摸屏输入,手势输入等),实现对正在开发的应用

Android自动化测试-UiAutomator环境搭建

Android自动化测试-UiAutomator环境搭建 一.环境准备 1. 安装android sdk,并配置环境变量 2. 安装android studio,国内访问官网受限,如果下载不到,可以到我的百度云盘下载: https://pan.baidu.com/s/1bpq5wK3 此云盘中有uiautomator2所依赖的jar包,可以同时下载 二.新建Android Studio工程 新建一个project,输入application name,下一步, 默认选择,下一步, 选择 empt

Android 自动化测试(5)&lt;robotium&gt;

关于Android的自动化测试之UI测试,之前介绍过Android 自动化测试(4)<uiautomator>, 在android原生的单元测试框架上,利用uiautomator.jar这个类库来完成Android的界面上的测试,这已经使得测试比较简单了.但还有更加简单的写测试的方式,那就是利用一些第三方的测试框架,比如robotium. Android的第三方的测试框架,有Robolectric 和 robotium,我试着用了下,觉得robotium已经非常好用了. 1.概要 Roboti

Android自动化测试课程大纲

Native App与Web App的自动化测试方法 Android自动化测试常用工具介绍 Robotium Android的Instrumentation机制 Robotium环境搭建及基本使用方法 Robotium基本API的使用 基于Robotium搭建测试框架 UIAutomator UIAutomator架构与原理介绍 UIAutomator环境搭建及基本使用方法 UIAutomator基本API的使用(案例演练) UiDevice UiSelector UiObject UiColl

android开发之-Android 开发之4.0界面设计原则-整理

设计原则: 一.让人着迷: 1.给人惊喜:使用漂亮的界面.精心的动画.适时的音乐. 2.真实的对象比按钮和菜单更有趣 这句话的意思是:使用描述描述性的图标作为快捷方式,界面美观 当然这个快捷方式是描述一个实体的,像一个人,不是扁平化的 3.个性化设计 提供个性化设计,提高亲切感和控制感.多设计几套个性化方案 4.记住人们的使用习惯,不要重复问 记住人们的使用习惯,不要重复问.多使用可以自动记住的控件,Autocomplete控件,不要每次询问操作 二.简单我的生活 1.使用简单词.短句子. 人们

Android自动化测试解决方案

现在,已经有大量的Android自动化测试架构或工具可供我们使用,其中包括:Activity Instrumentation, MonkeyRunner, Robotium, 以及Robolectric.另外LessPainful也提供服务来进行真实设备上的自动化测试. Android自身提供了对instrumentation测试的基本支持,其中之一就是位于android.test包内的ActivityInstrumentationTestCase2类,它扩展了JUnit的TestCase类来提

&lt;只看这个就够了。。。&gt;Android自动化测试及性能优化

Android自动化测试及性能优化 分类: Android Java Tools2012-12-09 23:31 4300人阅读 评论(0) 收藏 举报 软件自动化测试对于程序员来说能够确保软件开发的质量和效率.在Android编程中,Android集成了Junit单元测试框架,因此我们可以通过Junit来进行单元测试以及自动化测试. 1.引入Junit测试框架 在Manifest.xml配置文件中,我们需要引入Junit测试框架,因此需要在配置文件中添加如下代码: 在<application>