Android编程单元测试实例详解(附源码)
本文实例讲述了android编程单元测试。分享给大家供大家参考,具体如下:
完整实例代码代码点击此处本站下载。
本文是在上一篇文章《java编程之单元测试(junit)实例分析》的基础上继续讲解android的单元测试,android源码中引入了java单元测试的框架(android源码目录:libcore\junit\src\main\java\junit\framework中可见),然后在java单元测试框架的基础上扩展属于android自己的测试框架。android具体框架类的关系图如下:
从上图的类关系图中可以知道,通过android测试类可以实现对android中相关重要的组件进行测试(如activity,service,contentprovider,甚至是application)。
其实在android源码中,基本上每个系统应用都自带一个测试工程,如下图的源码中settings(设置)模块:
上图的tests文件夹中就是settings模块自带的单元测试工程,有兴趣的读者可自行去研读一下源代码。
eclipse下(当然,前提是要保证eclipse中相关的android环境已经搭建好)进行android单元测试:
1.application的测试:
新建一个android项目,在该android项目添加一个继承application的类,代码如下:
package com.phicomm.hu; import android.app.application; public class fxandroidapplication extends application { @override public void oncreate() { // todo auto-generated method stub super.oncreate(); } @override public void onterminate() { // todo auto-generated method stub super.onterminate(); } public string getfavourite() { return "i love java"; } }
appication类创建好后,接着创建对应的测试工程:选中其所在的android工程---->鼠标右键----->new---->android test project----->输入测试工程名--->next----->选择被测试的目标android工程(此处为fxandroidapplication所在的android工程)。这样,一个测试工程就创建完成了。
通过eclipse创建自动生成的测试工程项目和android工程项目结构上没什么大的区别,主要是在androidmanifest.xml中有变化,如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.phicomm.hu.test" android:versioncode="1" android:versionname="1.0" > <uses-sdk android:minsdkversion="10" /> <instrumentation android:name="android.test.instrumentationtestrunner" android:targetpackage="com.phicomm.hu" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <uses-library android:name="android.test.runner" /> </application> </manifest>
在androidmanifest.xml注册了相关的测试环境(这些是android独有的):<uses-library android:name="android.test.runner" />实现使用相关的运行测试类库,<instrumentation />中的targetpackage为被测试类所在的包。
接下来在测试工程中创建fxandroidapplicationd的测试类,代码如下:
package com.phicomm.hu.test; import com.phicomm.hu.fxandroidapplication; import android.app.application; import android.test.applicationtestcase; public class fxapplicationtest extends applicationtestcase<fxandroidapplication> { private fxandroidapplication apptest; public fxapplicationtest() { //调用父类构造函数,且构造函中传递的参数为被测试的类 super(fxandroidapplication.class); } @override protected void setup() throws exception { // todo auto-generated method stub super.setup(); //获取application之前必须调用的方法 createapplication(); //获取待测试的fxandroidapplication apptest = getapplication(); } //测试fxandroidapplication的getfavourite方法 public void testgetfavourite() { /*验证预测值"i love c++"是否等于实际值, 由于实际值为"i love java",所以此处测试结果为failure*/ assertequals("i love c++", apptest.getfavourite()); } }
测试类创建好后,就可以实现对fxandroidapplicationd进行测试了。
测试方法:
启动android模拟器(也可以通过android手机)----->运行android工程----->在测试工程中选中测试类fxapplicationtest---->鼠标右键--->run as---->android junit test。这样,测试结果就可以在eclipse的junit视图上显示了,如下图:
通过上图的测试结果可知,applicationtestcase测试类中有两个测试方法是默认进行测试的(testgetfavourite才是我们要测试的方法)。
当然,还可以通过adb进行测试:连接android手机------>打开电脑命令窗口(开始-->运行--->输入cmd)---->在命令窗口输入adb shell---->am instrument -w com.phicomm.hu.test(测试用例所在的包名)/android.test.instrumentationtestrunner。
2.activity的测试:
和上面application一样,先创建一个android工程,该工程中创建了两个activity,一个activity实现输入用户信息的登录界面,另一个acticity显示输入的用户信息。
效果图如下:
登录界面fxloginactivity的代码如下:
package com.phicomm.hu; import android.app.activity; import android.content.intent; import android.os.bundle; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; import android.widget.edittext; public class fxloginactivity extends activity { private edittext username; private edittext password; /** called when the activity is first created. */ @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); username = (edittext)findviewbyid(r.id.name); password = (edittext)findviewbyid(r.id.psd); button login = (button)findviewbyid(r.id.login); button reset = (button)findviewbyid(r.id.reset); //监听登录按钮 login.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { // todo auto-generated method stub intent intent = new intent(fxloginactivity.this, fxresultactivity.class); //通过intent传递登录信息到resultactivity的界面中显示 intent.putextra("username", username.gettext().tostring()); intent.putextra("password", password.gettext().tostring()); //启动resultactivity显示登录界面信息 startactivity(intent); } }); //监听重置按钮 reset.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { // todo auto-generated method stub resetinput(); } }); } public void resetinput() { username.settext(""); password.settext(""); } }
main.xml布局文件的代码如下:
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <edittext android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="@string/name"/> <edittext android:id="@+id/psd" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="@string/psd"/> <linearlayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" > <button android:id="@+id/login" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/login"/> <button android:id="@+id/reset" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/reset"/> </linearlayout> </linearlayout>
显示用户信息界面的fxresultactivity代码如下:
package com.phicomm.hu; import android.app.activity; import android.content.intent; import android.os.bundle; import android.util.log; import android.widget.edittext; import android.widget.textview; public class fxresultactivity extends activity { private static final string tag = "resultactivity"; @override protected void oncreate(bundle savedinstancestate) { // todo auto-generated method stub super.oncreate(savedinstancestate); setcontentview(r.layout.result); textview result = (textview)findviewbyid(r.id.result); //通过得到intent获取登录界面传来的信息 intent intent = getintent(); string username = intent.getstringextra("username"); string password = intent.getstringextra("password"); //将登录信息在页面中显示 result.settext("用户名:" + username + "\n" + "密码:" + password); } }
以上的android工程创建好后,创建一个对应的测试工程:
测试工程中对应的fxloginactivity类的测试代码如下(详细的代码讲解见代码中的相关注释,这里不在累赘):
package com.phicomm.hu.test; import android.app.instrumentation; import android.test.activityinstrumentationtestcase2; import android.view.keyevent; import android.widget.button; import android.widget.edittext; import com.phicomm.hu.fxloginactivity; public class fxloginactivitytest extends activityinstrumentationtestcase2<fxloginactivity> { private instrumentation minstrumentation; private fxloginactivity mlogintest; private edittext username; private edittext password; private button login; private button reset; public fxloginactivitytest() { super(fxloginactivity.class); } //重写setup方法,在该方法中进行相关的初始化操作 @override protected void setup() throws exception { // todo auto-generated method stub super.setup(); /**这个程序中需要输入用户信息和密码,也就是说需要发送key事件, * 所以,必须在调用getactivity之前,调用下面的方法来关闭 * touch模式,否则key事件会被忽略 */ //关闭touch模式 setactivityinitialtouchmode(false); minstrumentation = getinstrumentation(); //获取被测试的fxloginactivity mlogintest = getactivity(); //获取fxloginactivity相关的ui组件 username = (edittext)mlogintest.findviewbyid(com.phicomm.hu.r.id.name); password = (edittext)mlogintest.findviewbyid(com.phicomm.hu.r.id.psd); login = (button)mlogintest.findviewbyid(com.phicomm.hu.r.id.login); reset = (button)mlogintest.findviewbyid(com.phicomm.hu.r.id.reset); } //该测试用例实现在测试其他用例之前,测试确保获取的组件不为空 public void testpreconditions() { assertnotnull(mlogintest); assertnotnull(username); assertnotnull(password); assertnotnull(login); assertnotnull(reset); } /**该方法实现在登录界面上输入相关的登录信息。由于ui组件的 * 相关处理(如此处的请求聚焦)需要在ui线程上实现, * 所以需调用activity的runonuithread方法实现。 */ public void input() { mlogintest.runonuithread(new runnable() { @override public void run() { // todo auto-generated method stub username.requestfocus(); username.performclick(); } }); /*由于测试用例在单独的线程上执行,所以此处需要同步application, * 调用waitforidlesync等待测试线程和ui线程同步,才能进行输入操作。 * waitforidlesync和sendkeys不允许在ui线程里运行 */ minstrumentation.waitforidlesync(); //调用sendkeys方法,输入用户名 sendkeys(keyevent.keycode_p, keyevent.keycode_h, keyevent.keycode_i, keyevent.keycode_c, keyevent.keycode_o, keyevent.keycode_m, keyevent.keycode_m); mlogintest.runonuithread(new runnable() { @override public void run() { // todo auto-generated method stub password.requestfocus(); password.performclick(); } }); //调用sendkeys方法,输入密码 sendkeys(keyevent.keycode_1, keyevent.keycode_2, keyevent.keycode_3, keyevent.keycode_4); } //测试输入的用户信息 public void testinput() { //调用测试类的input方法,实现输入用户信息(sendkeys实现输入) input(); //测试验证用户信息的预期值是否等于实际值 assertequals("phicomm", username.gettext().tostring()); //密码的预期值123与实际值1234不符,failure; assertequals("123", password.gettext().tostring()); } //测试登录按钮 public void testlogin() { input(); //开新线程,并通过该线程在实现在ui线程上执行操作 minstrumentation.runonmainsync(new runnable() { @override public void run() { // todo auto-generated method stub login.requestfocus(); login.performclick(); } }); } //测试重置按钮 public void testreset() { input(); minstrumentation.runonmainsync(new runnable() { @override public void run() { // todo auto-generated method stub reset.requestfocus(); //点击按钮 reset.performclick(); } }); //验证重置按钮的实现功能,是否点击后内容为空 assertequals("", username.gettext().tostring()); assertequals("", password.gettext().tostring()); } }
运行该测试类进行测试(选中---->run as--->android junit test),然后会自动启动模拟器进行相关的输入点击测试。注:测试时可以发现,程序在测试到testlogin()方法登录到另一个界面时,测试就停止了,也就是说testreset()没测试到。所以,需要测试testreset()时可以先把testlogin()注释掉,不然程序会测试到testlogin()后就不在对testreset()进行测试。
fxresultactivity的测试类代码如下:
package com.phicomm.hu.test; import android.content.intent; import android.test.activityinstrumentationtestcase2; import android.widget.textview; import com.phicomm.hu.fxresultactivity; public class fxresultactivitytest extends activityinstrumentationtestcase2<fxresultactivity> { private static final string login_info = "用户名:feixun\n密码:123"; private fxresultactivity mresultactivity; private textview result; public fxresultactivitytest() { super(fxresultactivity.class); } @override protected void setup() throws exception { // todo auto-generated method stub super.setup(); //创建intent,通过intent传递用户的登录信息 intent intent = new intent(); intent.putextra("username", "feixun"); intent.putextra("password", "123"); //通过携带用户登录信息的intent启动fxresultactivity mresultactivity = launchactivitywithintent("com.phicomm.hu", fxresultactivity.class, intent); //获取ui组件 result = (textview)mresultactivity.findviewbyid(com.phicomm.hu.r.id.result); } //测试验证用户的登录信息 public void testlogininfo() { //验证预期值是否等于实际值 assertequals(login_info, result.gettext().tostring()); } }
运行上面的测试类,结果正确。
希望本文所述对大家android程序设计有所帮助。