通过AndroidTestCase来进行android 单元测试
文章转载于chinaunix的易水工作室
在以前的博客中介绍过了如何用intrumentation进行android单元测试,其实还有一种方法同样可以,那就是利用AndroidTestCase来做单元测试,intrumentationTestCase和AndroidTestCase都是Junit.framwork.TestCase的子类,二者代表不用的方向。
如果想通过AndroidTestCase,大致可以通过以下几个步骤实现:
添加自己的test case code,让他们继承自AndroidTestCase。
定义自己的testSuite类,用来管理test cases.
定义自己的testRunner,用来执行测试
下面首先来看一下这种方法所涉及到的android的类以及接口。
AndroidTestCase
Android test cases classes需要从这个类派生出来,而不再是从junit.framework.TestCase.二者之间的最主要区别就是Android test cases提供了一个方法getContext()来获取当前的上下文变量,这在android测试中很重要的,因为很多的android api都需要context。
AndroidTestCase主要成员:
setUp()//Setsupthefixture,forexample,openanetworkconnection.tearDown()//Tearsdownthefixture,forexample,closeanetworkconnection.testAndroidTestCaseSetupProperly()
TestSuite(in package junit.package)
一个TestSuite
就是一系列
test case
的集合。通过
testsuite
可以更好的来管理
test case
TestSuite主要成员:
VoidaddTest (Test test) //Adds a test to the suite.
voidaddTestSuite(Class testClass)//Adds the tests from the given class to the suite
下面是一小段往test suite中添加test case的示例:
TestSuitesuite=newTestSuite();suite.addTest(newMathTest("testAdd"));//Addsatesttothesuite.suite.addTest(newMathTest("testDivideByZero"));//或者可以通过addTestSuite()来添加suite.addTestSuite(MathTest.class);
TestListener(in package junit.framework)
这是一个interface,用来监听测试进程
有以下4个Public Methods:
abstractvoidaddError(Testtest,Throwablet)//Anerroroccurred.abstractvoidaddFailure(Testtest,AssertionFailedErrort)//Afailureoccurred.abstractvoidendTest(Testtest)//Atestended.abstractvoidstartTest(Testtest)//Ateststarted.
AndroidTestRunner
继承自class junit.runner.BaseTestRunner,但是它没有提供ui,甚至来一个基于console的UI都没有,所以,如果想要很好的查看测试结果的话,你需要自己来处理来自于test runner的callback函数。一会可以通过例子演示一下
AndroidTestRunner主要方法:
SetTest();runTest()addTestListener()setContext()
如果要使用AndroidTestRunner,需要在permission in manifest.xml中添加权限:
<uses-libraryandroid:name="android.test.runner"/>
最后,通过一个实例来演示一下:
1. 写一个test case:
MathTest.java
packagecom.ut.prac;importandroid.test.AndroidTestCase;importandroid.util.Log;publicclassMathTestextendsAndroidTestCase{protectedinti1;protectedinti2;staticfinalStringLOG_TAG="MathTest";publicvoidsetUp(){i1=2;i2=3;}publicvoidtestAdd(){Log.d(LOG_TAG,"testAdd");assertTrue(LOG_TAG+"1",((i1+i2)==5));}publicvoidtestAndroidTestCaseSetupProperly(){super.testAndroidTestCaseSetupProperly();Log.d(LOG_TAG,"testAndroidTestCaseSetupProperly");}}
2. 定义一个test suite类。
ExampleSuite.java
packagecom.ut.prac;importjunit.framework.TestSuite;publicclassExampleSuiteextendsTestSuite{publicExampleSuite(){addTestSuite(MathTest.class);}}
3.定义test runner,以及构建UI来处理测试流程,查看测试结果等。
MyJUnitExample.java
packagecom.ut.prac;importjunit.framework.Test;importjunit.framework.TestListener;importandroid.app.Activity;importandroid.os.Bundle;importandroid.test.AndroidTestRunner;importandroid.util.Log;importandroid.view.View;importandroid.widget.Button;importandroid.widget.TextView;importandroid.widget.Toast;publicclassMyJUnitExampleextendsActivity{staticfinalStringLOG_TAG="junit";ThreadtestRunnerThread=null;/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);ButtonlauncherButton=(Button)findViewById(R.id.launch_button);launcherButton.setOnClickListener(newView.OnClickListener(){publicvoidonClick(Viewview){startTest();}});}privatesynchronizedvoidstartTest(){if((testRunnerThread!=null)&&!testRunnerThread.isAlive())testRunnerThread=null;if(testRunnerThread==null){testRunnerThread=newThread(newTestRunner(this));testRunnerThread.start();}elseToast.makeText(this,"Testisstillrunning",Toast.LENGTH_SHORT).show();}}classTestDisplayimplementsRunnable{publicenumdisplayEvent{START_TEST,END_TEST,ERROR,FAILURE,}displayEventev;StringtestName;inttestCounter;interrorCounter;intfailureCounter;TextViewstatusText;TextViewtestCounterText;TextViewerrorCounterText;TextViewfailureCounterText;publicTestDisplay(displayEventev,StringtestName,inttestCounter,interrorCounter,intfailureCounter,TextViewstatusText,TextViewtestCounterText,TextViewerrorCounterText,TextViewfailureCounterText){this.ev=ev;this.testName=testName;this.testCounter=testCounter;this.errorCounter=errorCounter;this.failureCounter=failureCounter;this.statusText=statusText;this.testCounterText=testCounterText;this.errorCounterText=errorCounterText;this.failureCounterText=failureCounterText;}publicvoidrun(){StringBufferstatus=newStringBuffer();switch(ev){caseSTART_TEST:status.append("Starting");break;caseEND_TEST:status.append("Ending");break;caseERROR:status.append("Error:");break;caseFAILURE:status.append("Failure:");break;}status.append(":");status.append(testName);statusText.setText(newString(status));testCounterText.setText("Tests:"+testCounter);errorCounterText.setText("Errors:"+errorCounter);failureCounterText.setText("Failure:"+failureCounter);}}classTestRunnerimplementsRunnable,TestListener{staticfinalStringLOG_TAG="TestRunner";inttestCounter;interrorCounter;intfailureCounter;TextViewstatusText;TextViewtestCounterText;TextViewerrorCounterText;TextViewfailureCounterText;ActivityparentActivity;publicTestRunner(ActivityparentActivity){this.parentActivity=parentActivity;}publicvoidrun(){testCounter=0;errorCounter=0;failureCounter=0;statusText=(TextView)parentActivity.findViewById(R.id.status);testCounterText=(TextView)parentActivity.findViewById(R.id.testCounter);errorCounterText=(TextView)parentActivity.findViewById(R.id.errorCounter);failureCounterText=(TextView)parentActivity.findViewById(R.id.failureCounter);Log.d(LOG_TAG,"Teststarted");AndroidTestRunnertestRunner=newAndroidTestRunner();testRunner.setTest(newExampleSuite());testRunner.addTestListener(this);testRunner.setContext(parentActivity);testRunner.runTest();Log.d(LOG_TAG,"Testended");}//TestListenerpublicvoidaddError(Testtest,Throwablet){Log.d(LOG_TAG,"addError:"+test.getClass().getName());Log.d(LOG_TAG,t.getMessage(),t);++errorCounter;TestDisplaytd=newTestDisplay(TestDisplay.displayEvent.ERROR,test.getClass().getName(),testCounter,errorCounter,failureCounter,statusText,testCounterText,errorCounterText,failureCounterText);parentActivity.runOnUiThread(td);}publicvoidendTest(Testtest){Log.d(LOG_TAG,"endTest:"+test.getClass().getName());TestDisplaytd=newTestDisplay(TestDisplay.displayEvent.END_TEST,test.getClass().getName(),testCounter,errorCounter,failureCounter,statusText,testCounterText,errorCounterText,failureCounterText);parentActivity.runOnUiThread(td);}publicvoidstartTest(Testtest){Log.d(LOG_TAG,"startTest:"+test.getClass().getName());++testCounter;TestDisplaytd=newTestDisplay(TestDisplay.displayEvent.START_TEST,test.getClass().getName(),testCounter,errorCounter,failureCounter,statusText,testCounterText,errorCounterText,failureCounterText);parentActivity.runOnUiThread(td);}@OverridepublicvoidaddFailure(Testtest,junit.framework.AssertionFailedErrort){//TODOAuto-generatedmethodstubLog.d(LOG_TAG,"addFailure:"+test.getClass().getName());Log.d(LOG_TAG,t.getMessage(),t);++failureCounter;TestDisplaytd=newTestDisplay(TestDisplay.displayEvent.FAILURE,test.getClass().getName(),testCounter,errorCounter,failureCounter,statusText,testCounterText,errorCounterText,failureCounterText);parentActivity.runOnUiThread(td);}}
4. 最后是xml文件
Manifest.xml
<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.ut.prac"android:versionCode="1"android:versionName="1.0"><uses-permissionandroid:name="android.permission.WRITE_CONTACTS"/><uses-permissionandroid:name="android.permission.READ_CONTACTS"/><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><uses-libraryandroid:name="android.test.runner"/><activityandroid:name=".MyJUnitExample"android:label="@string/app_name"><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter></activity></application><uses-sdkandroid:minSdkVersion="3"/></manifest>
Mail.xml
<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><Buttonandroid:id="@+id/launch_button"android:text="@string/launch_test"android:layout_width="wrap_content"android:layout_height="wrap_content"/><TextViewandroid:id="@+id/status"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text=""/><TextViewandroid:id="@+id/testCounter"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text=""/><TextViewandroid:id="@+id/errorCounter"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text=""/><TextViewandroid:id="@+id/failureCounter"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text=""/></LinearLayout>
更多相关文章
- 如何添加Android返回键的退出功能
- Android(安卓)init.rc BOOTCLASSPATH
- 2011.09.13(3)——— android 添加快捷方式并且图标上添加数字
- android自定义属性之format介绍
- 去掉所有Activity界面标题栏、强制横屏竖屏
- Android(安卓)Makefile中是 如何识别 TARGET_PRODUCT 的
- android 完美退出所有Activity的demo
- Android(安卓)自定义带圆角的dialog
- Android之自定义ContentProvider详解