求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
Android自动化测试及性能优化
 

发布于2013-5-29

 

软件自动化测试对于程序员来说能够确保软件开发的质量和效率。在Android编程中,Android集成了Junit单元测试框架,因此我们可以通过Junit来进行单元测试以及自动化测试。

1、引入Junit测试框架

在Manifest.xml配置文件中,我们需要引入Junit测试框架,因此需要在配置文件中添加如下代码:

在<application>标签中添加Junit测试库:

<uses-library android:name="android.test.runner" />

在<manifest>标签中添加以下代码:

    <instrumentation
android:name="android.test.InstrumentationTestRunner"
android:label="Tests for My App"
android:targetPackage="com.jony.androidtestdemo" />

其中android:name="android.test.InstrumentationTestRunner"表示引入Android测试类

android:label="Tests for My App"该属性的具体内容根据实际情况自行定义

android:targetPackage="com.jony.androidtestdemo"该属性定义了需要测试的包名

至此,进行单元测试需要配置的工作就全部完成了。接下来简单写几个测试用的Activity——模拟实现用户登录过程

2、业务代码编写

MainActivity.java主要作用是实现Activity界面的跳转,通过点击界面上的Button按钮,跳转到用户登录界面;

LoginActivity.java主要作用是接收用户输入的用户名和密码;

HomeActivity.java用户登录成功界面。

以上三个界面的逻辑非常简单,本文重点在于讲解Android自动化测试以及性能优化,因此复杂的业务逻辑在此就不做过多介绍。

3、单元测试

在进行单元测试前,大家可能最关注的是:怎样获得Activity的实例?

的确,这个问题是我们必须要关心的。既然我们能想到的问题,想必Android的大牛们已经给我们提供了怎么获得Activity实例的方法了。

在Android单元测试中,我们只要继承ActivityInstrumentationTestCase2 类,在其构造函数中传入需要测试的Activity,就能通过getActivity()方法获得我们需要测试的Activity的实例,具体代码如下所示:

MainActivity.java的测试代码如下所示:

   package com.jony.androidtestdemo.test;
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import android.view.View;
import com.jony.androidtestdemo.MainActivity;
import com.jony.androidtestdemo.R;
public class MainActivityTest extends
ActivityInstrumentationTestCase2<MainActivity> {
private static final String TAG = "MainActivityTest";
private Instrumentation mInstrument;
private MainActivity mActivity;
private View mToLoginView;
public MainActivityTest() {
super(MainActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
mInstrument = getInstrumentation();
// 启动被测试的Activity
mActivity = getActivity();
mToLoginView = mActivity.findViewById(R.id.to_login);
}
public void testPreConditions() {
// 在执行测试之前,确保程序的重要对象已被初始化
assertTrue(mToLoginView != null);
}
// mInstrument.runOnMainSync(new Runnable() {
// public void run() {
// mToLoginView.requestFocus();
// mToLoginView.performClick();
// }
// });
@UiThreadTest
public void testToLogin() {
// @UiThreadTest注解使整个方法在UI线程上执行,等同于上面注解掉的代码
mToLoginView.requestFocus();
mToLoginView.performClick();
}
@Suppress
public void testNotCalled() {
// 使用了@Suppress注解的方法不会被测试
Log.i(TAG, "method 'testNotCalled' is called");
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
}

LoginActivity.java测试代码如下所示:

package com.jony.androidtestdemo.test;
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import com.jony.androidtestdemo.LoginActivity;
import com.jony.androidtestdemo.R;
public class LoginActivityTest extends
ActivityInstrumentationTestCase2<LoginActivity> {
private static final String TAG = "LoginActivityTest";
private Instrumentation mInstrument;
private LoginActivity mActivity;
private EditText mUsernameView;
private EditText mPasswordView;
private View mSubmitView;
private View mResetView;
public LoginActivityTest() {
super(LoginActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
/*
* 要向程序发送key事件的话,必须在getActivity之前调用该方法来关闭touch模式
* 否则key事件会被忽略
*/
setActivityInitialTouchMode(false);
mInstrument = getInstrumentation();
mActivity = getActivity();
Log.i(TAG, "current activity: " + mActivity.getClass().getName());
mUsernameView = (EditText) mActivity.findViewById(R.id.username);
mPasswordView = (EditText) mActivity.findViewById(R.id.password);
mSubmitView = mActivity.findViewById(R.id.submit);
mResetView = mActivity.findViewById(R.id.reset);
}
public void testPreConditions() {
assertTrue(mUsernameView != null);
assertTrue(mPasswordView != null);
assertTrue(mSubmitView != null);
assertTrue(mResetView != null);
}
public void testInput() {
input();
assertEquals("1231", mUsernameView.getText().toString());
assertEquals("11", mPasswordView.getText().toString());
}
public void testSubmit() {
input();
mInstrument.runOnMainSync(new Runnable() {
public void run() {
mSubmitView.requestFocus();
mSubmitView.performClick();
}
});
}
public void testReset() {
input();
mInstrument.runOnMainSync(new Runnable() {
public void run() {
mResetView.requestFocus();
mResetView.performClick();
}
});
assertEquals("", mUsernameView.getText().toString());
assertEquals("", mPasswordView.getText().toString());
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
private void input() {
mActivity.runOnUiThread(new Runnable() {
public void run() {
mUsernameView.requestFocus();
}
});
// 因为测试用例运行在单独的线程上,这里最好要
// 同步application,等待其执行完后再运行
mInstrument.waitForIdleSync();
sendKeys(KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_2,
KeyEvent.KEYCODE_3);
// 效果同上面sendKeys之前的代码
mInstrument.runOnMainSync(new Runnable() {
public void run() {
mPasswordView.requestFocus();
}
});
sendKeys(KeyEvent.KEYCODE_1);
}
}

HomeActivity.java测试代码如下所示:

package com.jony.androidtestdemo.test;
import android.content.Intent;
import android.test.ActivityUnitTestCase;
import android.widget.TextView;
import com.jony.androidtestdemo.HomeActivity;
import com.jony.androidtestdemo.R;
public class HomeActivityTest extends ActivityUnitTestCase<HomeActivity> {
private static final String TAG = "HomeActivityTest";
private static final String LOGIN_CONTENT = "username:1231\npassword:11";
private HomeActivity mHomeActivity;
private TextView mLoginContentView;
public HomeActivityTest() {
super(HomeActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
Intent intent = new Intent();
intent.putExtra(HomeActivity.EXTRA_USERNAME, "1231");
intent.putExtra(HomeActivity.EXTRA_PASSWORD, "11");
// HomeActivity有extra参数,所以我们需要以intent来启动它
mHomeActivity = launchActivityWithIntent("com.jony.androidtestdemo",
HomeActivity.class, intent);
mLoginContentView = (TextView) mHomeActivity
.findViewById(R.id.login_content);
}
public void testLoginContent() {
assertEquals(LOGIN_CONTENT, mLoginContentView.getText().toString());
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
}

到此,简单的测试代码就完成了,接下来就是验证代码能否正常运行。

首先,需要将Android应用程序安装到手机或者模拟器上面才能运行测试代码,打开Eclipse的Outline窗口,选中需要测试的方法,单击右键选择Run As-->Android Junit Test

如果出现下图的绿色状态栏则说明运行成功。

Android性能测试

在Android的SDK的tools 目录中,Android为我们提供了一个性能测试工具traceview,通过traceview功能我们能够确切了解每个方法执行的时间,调用次数以及递归调用测试等信息。通过分析各方法的调用时间可以了解系统的瓶颈,提升系统性能。

使用方法:

在需要进行性能分析的Activity中加入以下代码(一般在Activity的onCreate()方法中添加):

Debug.startMethodTracing("jonytest");//jonytest.trace

在onDestroy()方法中添加:

Debug.stopMethodTracing();// 停止数据采集

运行程序,当程序运行到该Activity是,系统会自动记录该Activity的所调用的所有方法的信息,并生成jonytest.trace文件保存在SDcard中。将该文件导出到电脑C盘,运行以下命令:traceview jonytest.trace 系统将会弹出如图所示窗口(可以在Find窗口查找具体方法(目前只支持小写)):

至此,Android单元测试和系统优化已经给大家介绍完了,知识融会贯通,希望对大家有所帮助。

相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程
 
分享到
 
 


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...