测试与优化

小组成员: 丁泽武,盛啸然,谢峰,高参,李智博   最终完成日期:15年00月00日

一、简介

       软件测试:在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。同样,Android的测试也是一种实际输出与预期输出间的审核或者比较过程。
       Android的测试大致分为三大块:

  • 1.代码层测试;
  • 2.用户操作模拟,功能测试;
  • 3.稳定性测试。

       本文将介绍以上三种测试,其中着重介绍如何使用Robotium来模拟用户的操作完成测试。

二、基础知识

  • 代码层测试:

       存在Application、Activity、Service等特殊组件,而这些组件都涉及到生命周期管理的问题。为了对这些组件进行测试,Google提供了一套针对性的测试框架,AndroidTestFramework。

       官方教程链接 http://developer.android.com/training/testing.html

       官方api http://developer.android.com/reference/android/test/package-summary.html

       其中最为常用的就是针对Activity的测试,即ActivityInstrumentationTestCase2类。继承该类后可通过getActivity()方法获取Activity的一个mock对象,从而实现各种界面元素的测试。代码如下:

public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
    LoginActivityTest mActivity;
    Button btnLogin;

    public LoginActivityTest(){
  super(LoginActivity.class);//必须实现super(testclass)
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        mActivity = getActivity();
                btnLogin = mActivity.findViewById(R.id.btnLogin);
    }

    public void testGetActivity(){
       assertNotNull("can't get LoginActivity" , mActivity);
       assertNotNull("can't get loginButton" , btnLogin);
    }
}

       需要注意的是,测试代码运行的线程并不是UI线程。因此如果需要对UI元素进行setText或是click之类的操作,需要通过getActivity().runOnUiThread(action)方法执行。代码如下:

getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                 btnLogin.click();
            }
        });
  • 用户操作模拟测试:

       虽然AndroidTestFramework可以帮助我们完成各种界面的测试。但是,这些代码的编写非常繁琐。而且在大部分情况下,我们需要的是一个连贯性的,在多个Activity之间存在跳转的业务流程测试。Robotium是一款国外的Android自动化测试的框架,主要针对Android平台的应用进行黑盒自动化测试,它提供了模拟各种手势操作(点击、长按、滑动等)、查找和断言机制的API,能够对各种控件进行操作。它在有源码是可以测试源码,进行白盒测试;没有源码时,只有一个应用程序的apk也可以对其进行黑盒测试。Robotium结合Android官方提供的测试框架达到对应用程序进行自动化的测试。

       源码及相关资料地址:https://code.google.com/p/robotium/

       Robotium具有清晰的调用方法、良好的兼容性、完善的文档和大量的实际应用案例,并且支持截屏。最为符合我们目前的实际需求。

  • 稳定性测试:

       安卓系统最为让人诟病的问题就是碎片化,这点在中国比较明显。大致上,2.3.X 和 4.x 的系统各占半壁江山,此外还存在大量的山寨定制系统。因此在这推荐两款云端测试工具,Testin和百度云测试。两个框架测试都很简单,在官网注册账号后上传apk即可,网站会用大量的真机进行安装部署和monkey测试。测试完成后会发送一份测试给注册邮箱。Testin支持Robotium框架的代码测试,同时上传项目apk和测试apk(相同签名)即可。

       Testin地址: http://www.testin.cn/

       百度云测试: http://mtc.baidu.com/

三、主要思路及步骤

3.1 主要思路

       下面主要介绍如何使用Robotium进行自动化测试,测试的思路为:设置一个按钮Button和文本框TextView,然后使用Robotium模拟点击Button,之后调用Button的onClick事件修改TextView的text属性值。在测试代码中监测TextView的text属性值是否与预期的属性值相等。同时还测试了Robotium的其他功能,比如使用Button的text属性查找Button等。

3.2 实践步骤

       下面将会介绍如何在Android Studio中创建Robotium测试的步骤:

  • 1.创建一个工程,命名为TestRobotium;
  • 2.在app下的build.gradle文件中加入dependencies,如下所示:
androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.1'
  • 3.在androidTest目录下创建MainActivityTest类,如下图所示:
  • 4.在主界面上面放置四个按钮,用以使用Robotium模拟对按钮的点击事件。修改activity_main.xml文件,代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_test"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Click me"
        android:onClick="onClikcMe"/>
    <TextView
        android:id="@+id/show_test"
        android:text="@string/hello_world"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/btn_test"/>
    <EditText
        android:id="@+id/insertText"
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:layout_below="@+id/show_test"
        />
    <Button
        android:id="@+id/btn_test1"
        android:layout_below="@+id/insertText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="绿色"
        android:onClick="onClikcMe1"/>
    <Button
        android:id="@+id/btn_test2"
        android:layout_below="@id/btn_test1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="黄色"
        android:onClick="onClikcMe2"/>
    <Button
        android:id="@+id/btn_test3"
        android:layout_below="@id/btn_test2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="蓝色"
        android:onClick="onClikcMe3"/>

</RelativeLayout>
  • 5.在MainActivity.java文件中添加按钮的点击事件,代码如下:
public void onClikcMe(View view){
        TextView textView = (TextView)findViewById(R.id.show_test);
        textView.setText("hi");
    }

    public void onClikcMe1(View view){
        TextView textView = (TextView)findViewById(R.id.show_test);
        textView.setText("hi1");
    }

    public void onClikcMe2(View view){
        TextView textView = (TextView)findViewById(R.id.show_test);
        textView.setText("hi2");
    }

    public void onClikcMe3(View view){
        TextView textView = (TextView)findViewById(R.id.show_test);
        textView.setText("hi3");
    }
  • 6.接下来我们就可以模拟点击按钮的事件了。在MainActivityTest.java类当中写点击按钮的测试,代码如下:

package com.pku.lesshst.testrobotium;
import android.test.ActivityInstrumentationTestCase2;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.robotium.solo.Solo;
/**
 * Created by lesshst on 2015/11/30.
 */
public class MainActivityTest extends ActivityInstrumentationTestCase2{
    private Solo solo;

    public MainActivityTest() {
        super(MainActivity.class);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        solo = new Solo(getInstrumentation(), getActivity());
    }

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

    public void test_MainActivityChangeTextView_hi() throws Exception {
        //等待  Activity "MainActivity" 启动
        assertTrue("无法启动启动类", solo.waitForActivity("MainActivity", 30000));
        solo.sleep(5000);
        //choose environment
        Button btn_test = (Button)solo.getView(R.id.btn_test);
        solo.clickOnView(btn_test);
        solo.waitForText("hi", 1, 5000);
        TextView tv = (TextView)solo.getView(R.id.show_test);
        String result = tv.getText().toString();
        assertEquals(result, "hi");
        solo.sleep(2000);
        //输入文字:"131243"
        solo.enterText((EditText)solo.getView("insertText"), "这是一个测试!");
        solo.sleep(2000);

        //清空输入框的内容
        solo.clearEditText((EditText) solo.getView("insertText"));

        //按下 按钮 "绿色"
        solo.clickOnButton("^绿色$");
        solo.waitForText("hi1", 1, 5000);
        result = tv.getText().toString();
        assertEquals(result, "hi1");
        solo.sleep(2000);

        //按下 按钮 "黄色"
        solo.clickOnButton("^黄色$");
        solo.waitForText("hi2", 1, 5000);
        result = tv.getText().toString();
        assertEquals(result, "hi2");
        solo.sleep(2000);

        //按下 按钮 "蓝色"
        solo.clickOnButton("^蓝色$");
        solo.waitForText("hi3", 1, 5000);
        result = tv.getText().toString();
        assertEquals(result, "hi1");
        solo.sleep(2000);
    }
}
  • 7.测试配置:点击菜单Run->Edit Configurations...,在Run/Debug Configurations窗口当中添加一个Android Tests,1、名字可以随意取;2、Module选择app;3、Test选择All in Module;4、Target Device选择Show chooser dialog。如下图所示:
  • 8.如下图所示选择刚刚创建的Android Test
  • 9.点击运行按钮即可完成自动化测试。
  • 10.运行结果分析: 由上图可以看到,我们的test测试出了问题。这句代码(见下面)assertEquals语句出错,也就是当点击显示字符为“蓝色”的按钮后TextView的text属性值发生变化,但是其属性值与我们设想的值“hi1”不同,所以在此项测试当中发现这种不一致,达到测试的目的。
    solo.clickOnButton("^蓝色$");
    solo.waitForText("hi3", 1, 5000);
    result = tv.getText().toString();
    assertEquals(result, "hi1");
    solo.sleep(2000);

四、常见问题及注意事项

  • 1.如何获取、区分具有相同id的多个控件?

       基本思路:当控件都是一样的情况下去寻找能够区别它们的东西,有下面的集中方法。

       方法1.ParentView(要找的控件对应的父布局)和index(控件位置);

       方法2.利用同级的具有唯一性的其他控件指定它们的ParentView,再通过父布局查找该控件;

       方法3.若控件有具有特殊性的文本信息,可直接根据文本信息获取控件。

results matching ""

    No results matching ""