添加自己的test case code, 让他们继承自AndroidTestCase。
定义自己的testSuite类,用来管理test cases.
定义自己的testRunner,用来执行测试
Android test cases classes需要从这个类派生出来,而不再是从junit.framework.TestCase. 二者之间的最主要区别就是Android test cases提供了一个方法getContext()来获取当前的上下文变量,这在android测试中很重要的,因为很多的android api都需要context。
AndroidTestCase主要成员:
setUp() //Sets up the fixture, for example, open a network connection. tearDown() //Tears down the fixture, for example, close a network connection. testAndroidTestCaseSetupProperly()
一个TestSuite
就是一系列
test case
的集合。通过
testsuite
可以更好的来管理
test case
TestSuite主要成员:
Void addTest (Test test) //Adds a test to the suite.
void addTestSuite(Class testClass) //Adds the tests from the given class to the suite
下面是一小段往test suite中添加test case的示例:
TestSuite suite= new TestSuite(); suite.addTest(new MathTest("testAdd")); //Adds a test to the suite. suite.addTest(new MathTest("testDivideByZero")); //或者可以通过addTestSuite()来添加 suite.addTestSuite(MathTest.class);
这是一个 interface ,用来监听测试进程
有以下4个Public Methods :
abstract void addError(Test test,Throwable t) //An error occurred. abstract void addFailure(Test test,AssertionFailedError t) //A failure occurred. abstract void endTest(Test test) //A test ended. abstract void startTest(Test test) //A test started.
继承自class junit.runner.BaseTestRunner,但是它没有提供ui, 甚至来一个基于console的UI都没有,所以,如果想要很好的查看测试结果的话,你需要自己来处理来自于test runner的callback 函数。一会可以通过例子演示一下
AndroidTestRunner主要方法:
SetTest(); runTest() addTestListener() setContext()
<uses-library android:name="android.test.runner"/>
最后,通过一个实例来演示一下:
1. 写一个test case:
MathTest.java
package com.ut.prac; import android.test.AndroidTestCase; import android.util.Log; public class MathTest extends AndroidTestCase { protected int i1; protected int i2; static final String LOG_TAG = "MathTest"; public void setUp() { i1 = 2; i2 = 3; } public void testAdd() { Log.d( LOG_TAG, "testAdd" ); assertTrue( LOG_TAG+"1", ( ( i1 + i2 ) == 5 ) ); } public void testAndroidTestCaseSetupProperly() { super.testAndroidTestCaseSetupProperly(); Log.d( LOG_TAG, "testAndroidTestCaseSetupProperly" ); } }
2. 定义一个test suite类。
ExampleSuite.java
package com.ut.prac; import junit.framework.TestSuite; public class ExampleSuite extends TestSuite { public ExampleSuite() { addTestSuite( MathTest.class ); } }
3. 定义test runner,以及构建UI来处理测试流程,查看测试结果等。
MyJUnitExample.java
package com.ut.prac; import junit.framework.Test; import junit.framework.TestListener; import android.app.Activity; import android.os.Bundle; import android.test.AndroidTestRunner; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MyJUnitExample extends Activity { static final String LOG_TAG = "junit"; Thread testRunnerThread = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button launcherButton = (Button)findViewById( R.id.launch_button ); launcherButton.setOnClickListener( new View.OnClickListener() { public void onClick( View view ) { startTest(); } } ); } private synchronized void startTest() { if( ( testRunnerThread != null ) && !testRunnerThread.isAlive() ) testRunnerThread = null; if( testRunnerThread == null ) { testRunnerThread = new Thread( new TestRunner( this ) ); testRunnerThread.start(); } else Toast.makeText( this, "Test is still running", Toast.LENGTH_SHORT).show(); } } class TestDisplay implements Runnable { public enum displayEvent { START_TEST, END_TEST, ERROR, FAILURE, } displayEvent ev; String testName; int testCounter; int errorCounter; int failureCounter; TextView statusText; TextView testCounterText; TextView errorCounterText; TextView failureCounterText; public TestDisplay( displayEvent ev, String testName, int testCounter, int errorCounter, int failureCounter, TextView statusText, TextView testCounterText, TextView errorCounterText, TextView failureCounterText ) { 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; } public void run() { StringBuffer status = new StringBuffer(); switch( ev ) { case START_TEST: status.append( "Starting" ); break; case END_TEST: status.append( "Ending" ); break; case ERROR: status.append( "Error: " ); break; case FAILURE: status.append( "Failure: " ); break; } status.append( ": " ); status.append( testName ); statusText.setText( new String( status ) ); testCounterText.setText( "Tests: "+testCounter ); errorCounterText.setText( "Errors: "+errorCounter ); failureCounterText.setText( "Failure: "+failureCounter ); } } class TestRunner implements Runnable,TestListener { static final String LOG_TAG = "TestRunner"; int testCounter; int errorCounter; int failureCounter; TextView statusText; TextView testCounterText; TextView errorCounterText; TextView failureCounterText; Activity parentActivity; public TestRunner( Activity parentActivity ) { this.parentActivity = parentActivity; } public void run() { 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, "Test started" ); AndroidTestRunner testRunner = new AndroidTestRunner(); testRunner.setTest( new ExampleSuite() ); testRunner.addTestListener( this ); testRunner.setContext( parentActivity ); testRunner.runTest(); Log.d( LOG_TAG, "Test ended" ); } // TestListener public void addError(Test test, Throwable t) { Log.d( LOG_TAG, "addError: "+test.getClass().getName() ); Log.d( LOG_TAG, t.getMessage(), t ); ++errorCounter; TestDisplay td = new TestDisplay( TestDisplay.displayEvent.ERROR, test.getClass().getName(), testCounter, errorCounter, failureCounter, statusText, testCounterText, errorCounterText, failureCounterText ); parentActivity.runOnUiThread( td ); } public void endTest(Test test) { Log.d( LOG_TAG, "endTest: "+test.getClass().getName() ); TestDisplay td = new TestDisplay( TestDisplay.displayEvent.END_TEST, test.getClass().getName(), testCounter, errorCounter, failureCounter, statusText, testCounterText, errorCounterText, failureCounterText ); parentActivity.runOnUiThread( td ); } public void startTest(Test test) { Log.d( LOG_TAG, "startTest: "+test.getClass().getName() ); ++testCounter; TestDisplay td = new TestDisplay( TestDisplay.displayEvent.START_TEST, test.getClass().getName(), testCounter, errorCounter, failureCounter, statusText, testCounterText, errorCounterText, failureCounterText ); parentActivity.runOnUiThread( td ); } @Override public void addFailure(Test test, junit.framework.AssertionFailedError t) { // TODO Auto-generated method stub Log.d( LOG_TAG, "addFailure: "+test.getClass().getName() ); Log.d( LOG_TAG, t.getMessage(), t ); ++failureCounter; TestDisplay td = new TestDisplay( TestDisplay.displayEvent.FAILURE, test.getClass().getName(), testCounter, errorCounter, failureCounter, statusText, testCounterText, errorCounterText, failureCounterText ); parentActivity.runOnUiThread( td ); } }
4. 最后是xml文件
Manifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ut.prac" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <uses-library android:name="android.test.runner" /> <activity android:name=".MyJUnitExample" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="3" /> </manifest>
Mail.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent"> <Button android:id="@+id/launch_button" android:text="@string/launch_test" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/status" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> <TextView android:id="@+id/testCounter" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> <TextView android:id="@+id/errorCounter" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> <TextView android:id="@+id/failureCounter" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> </LinearLayout>