在实际开发中,开发android软件的过程需要不断地进行测试。所以掌握Android的单元测试是极其重要的。您应该把单元测试作为Android应用开发周期的一部分,精心编写的测试可以在开发早起帮你发现错误。
关于Android单元测试可以看Google官方给的教程:Best Practices for Testing(需要FQ)
一、创建Android Test Project
1、创建一个Android Project:Hello。并将其布局文件改成如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 7 <TextView 8 android:id="@+id/text" 9 android:layout_width="match_parent" 10 android:layout_height="wrap_content" 11 android:text="@string/hello_world" /> 12 13 <!-- 这样直接写字符串是不好的,建议写在strings.xml中 --> 14 <EditText 15 android:id="@+id/edit" 16 android:layout_width="match_parent" 17 android:layout_height="wrap_content" 18 android:hint="请输入" /> 19 20 </LinearLayout>
2、创建Hello对应的测试项目:File->New->Other->Android->Android Test Project,弹出”New Android Test Project”对话框,在"Project Name"中输入“HelloTest”,点击“Next”。
3、在”Select Test Target”中,选中你要测试的Android项目,然后点击Finish即可。
创建完Android Test Project后,打开HelloTest项目的AndroidManifest.xml文件,你会发现里面的配置会比HelloTest多,具体不同请看下面的代码:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.lsj.hello.test" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk android:minSdkVersion="8" /> 8 9 <!-- 代表配置单元测试框架的启动装置,启动装置有好几个类,可以选择,一般情况下我们使用上面这个 --> 10 <!-- targetPackage与Hello的package相同,代表单元测试框架和当前应用是处于同一个进程中 --> 11 <instrumentation 12 android:name="android.test.InstrumentationTestRunner" 13 android:targetPackage="com.lsj.hello" /> 14 15 <application 16 android:icon="@drawable/ic_launcher" 17 android:label="@string/app_name" > 18 <!-- 代表把单元测试框架中的一些依赖库引入进来 --> 19 <uses-library android:name="android.test.runner" /> 20 </application> 21 22 </manifest>
二、单元测试代码编写
1、创建完Android Test Project后,你会发现HelloTest自动帮你创建了com.lsj.hello.tests的包名。关于Android单元测试相关包、类、方法的命名方式如下:
包名:com.lsj.example————com.lsj.example.tests//对应包名+".tests" 类名:Hello.java————HelloTest.java//对应类名+"Test" 方法名:Hello()————testHello()//"test"+对应方法名
2、在com.lsj.hello.tests包下建立MainActivityTest.java类,MainActivityTest继承自ActivityInstrumentationTestCase2,关于Android测试类可以看文章末尾的链接
3、编辑MainActivityTest,添加单元测试代码
1 package com.lsj.hello.test; 2 3 import android.app.Instrumentation; 4 import android.test.ActivityInstrumentationTestCase2; 5 import android.view.KeyEvent; 6 import android.widget.EditText; 7 import android.widget.TextView; 8 9 import com.lsj.hello.MainActivity; 10 11 /** 12 * ActivityInstrumentationTestCase2继承于TestCase, TestCase类位于junit.framework包下 13 * 查阅Android API文档,可以发现Android的测试类全部继承自TestCase。 创建一个单元测试大致需要以下步骤: 14 * 15 * <pre> 16 * 1、继承TestCase类或其子类 17 * 2、定义要使用到的实例变量 18 * 3、使用setUp()方法,在测试前的对变量和测试环境进行初始化 19 * ....测试 20 * 4、在测试完成后进行垃圾回收等善后工作 21 * </pre> 22 * 23 * @author Lion 24 */ 25 public class MainActivityTest extends 26 ActivityInstrumentationTestCase2<MainActivity> { 27 28 private MainActivity mActivity; 29 private TextView mTextView; 30 private EditText mEditText; 31 private Instrumentation mInstrumentation; 32 33 /** 34 * 重写MainActivityTest的构造方法,注意super内必须为<>内的泛型类,否则会报错。 35 * 根据Google官方给的示例,其构造函数为午餐,而且测试的时候发现有参的构造函数会导致单元测试失败。 36 */ 37 public MainActivityTest() { 38 super(MainActivity.class); 39 } 40 41 @Override 42 protected void setUp() throws Exception { 43 /* 执行对变量和测试环境的初始化 */ 44 super.setUp(); 45 // 关闭touch模式,否则key事件会被忽略 46 setActivityInitialTouchMode(false); 47 48 mInstrumentation = getInstrumentation(); 49 50 // 获取被测试的MainActivity 51 mActivity = this.getActivity(); 52 // 获取被测试的TextView控件 53 mTextView = (TextView) mActivity.findViewById(com.lsj.hello.R.id.text); 54 // 获取被测试的EditText控件 55 mEditText = (EditText) mActivity.findViewById(com.lsj.hello.R.id.edit); 56 } 57 58 /** 59 * 测试数据初始化是否为空 60 */ 61 public void testInit() { 62 // 断言mActivity是否为空 63 assertNotNull(mActivity); 64 // 断言mTextView是否为空 65 assertNotNull(mTextView); 66 // 断言mEditText是否为空 67 assertNotNull(mEditText); 68 } 69 70 /** 71 * 测试文本框字符串是否相等 72 */ 73 public void testTextViewString() { 74 // 断言mTextView显示的文本是否与String.xml中的hello_world相等 75 assertEquals( 76 mActivity.getResources().getString( 77 com.lsj.hello.R.string.hello_world), mTextView 78 .getText().toString()); 79 } 80 81 /** 82 * 测试输入 83 */ 84 public void testEditTextInput() { 85 input(); 86 assertEquals("hello", mEditText.getText().toString()); 87 } 88 89 /** 90 * 模拟输入 91 */ 92 public void input() { 93 /* UI组件的相关操作需要在UI线程上进行,所以用Activity的runOnUiThread方法 */ 94 mActivity.runOnUiThread(new Runnable() { 95 @Override 96 public void run() { 97 mEditText.requestFocus(); 98 mEditText.performClick(); 99 } 100 }); 101 /* 102 * 由于测试用例在单独的线程上执行,所以此处需要同步application, 103 * 调用waitForIdleSync等待测试线程和UI线程同步,才能进行输入操作。 104 * waitForIdleSync和sendKeys不允许在UI线程里运行 105 */ 106 mInstrumentation.waitForIdleSync(); 107 // 调用sendKeys方法,输入 108 sendKeys(KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_L, 109 KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_O); 110 } 111 112 @Override 113 protected void tearDown() throws Exception { 114 /* 在测试完成后进行垃圾回收等工作 */ 115 super.tearDown(); 116 } 117 }
这样,一个关于用户输入的单元测试就写完了,关于单元测试相关类的介绍可以查看这篇博客:Android Instrumentation
源码下载:百度云盘
作者:登天路