Android、JUnit深入浅出(五)——An…

前面我们学习了android.test包中的大部分类,是该通过学习具体的例子将前面的知识融会贯通,让我们的理解更加深刻,例子程序代码下载地址,下载后添加Eclipes的工程中,边看这篇文章边阅读例子程序的代码。

首先分析整个工程的结构图,如下:

example-class

AndroidTestCase,Testsuite在前面的篇幅中已经学习过了,ContestTest、MathTest、SomeTest、ExampleSuite在前面的例子中已经为大家介绍了,这里我们主要说明整个程序是如何运行的?

核心类代码简要列举,如下:

public class JUnit extends Activity {
static final String LOG_TAG = “junit”;
Thread testRunnerThread = null;

@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 TestRunner implements Runnable,TestListener
{
static final String LOG_TAG = “TestRunner”;
int testCounter;
int errorCounter;
int failureCounter;
……;
Activity parentActivity;

public TestRunner( Activity parentActivity )
{this.parentActivity = parentActivity;}

public void run()
{
testCounter = 0;
errorCounter = 0;
failureCounter = 0;
………….;

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;
…….;
}

public void addFailure(Test test, AssertionFailedError t)
{
Log.d( LOG_TAG, “addFailure: “+test.getClass().getName() );
Log.d( LOG_TAG, t.getMessage(), t );
++failureCounter;
…….;
}

public void endTest(Test test)
{
Log.d( LOG_TAG, “endTest: “+test.getClass().getName() );
…..;
}

public void startTest(Test test)
{
Log.d( LOG_TAG, “startTest: “+test.getClass().getName() );
++testCounter;
…….;
}

}
通过将源工程中的代码简单整理后,就可以看到TestRunner这个工作者线程(window中的术语,没有界面的线程)的作用,这让我们对TestListener有了更加深入的了解。

整个程序的核心代码,如下:

public void run()
{
……;

AndroidTestRunner testRunner = new AndroidTestRunner();
testRunner.setTest( new ExampleSuite() );
testRunner.addTestListener( this );
testRunner.setContext( parentActivity );
testRunner.runTest();
…….;
}

AndroidTestRunner这个核心类,在前面的篇幅中我们已经学习过,再次回忆下这张图(在大脑中留下深刻的记忆,后面会经常使用):

androidtestrunner

红色划线部分代表例子程序代码中使用的AndroidTestRunner类的函数。这里使用单独线程的主要作用就是:testRunner.runTest();会占用大量的时间,如果直接在UI线程中运行会阻滞UI线程,导致界面停止反应,这对用户的操作会有很大的影响。

如何将TestRunner 中的测试信息显示在界面上?

在前面的Snake例子程序中介绍过:Android SDK为我们提供了Handler,通过Handler与一个线程的消息队列相关联,发送和处理信息。在这个例子中使用了Activity类的runOnUiThread(Runnableaction)函数,这个函数的主要功能:在UI线程中运行指定的操作,如果当前线程是UI线程,然后采取行动立即执行;如果当前线程不是UI线程,发送消息到UI线程的事件队列。

整个程序就介绍完了,运行程序后的界面如下:
run

在这里需要特殊说明的是:打开AndroidManifest.xml文件,发现<application>有个以前没有见过的标记,如下:
<applicationandroid:label=”@string/app_name”>
<uses-libraryandroid:name=”android.test.runner”/>
<activity android:name=”.JUnit”android:label=”@string/app_name”>
<intent-filter>
<action android:name=”android.intent.action.MAIN”/>
<categoryandroid:name=”android.intent.category.LAUNCHER”/>
</intent-filter>
</activity>
</application>
user-library元素说明:指定一个共享库,应用程序需要连接的。默认情况下会连接所有的Android库,然而一些软件包(如地图和AWT)是不会自动连接独立的库,以确定哪些库需要包含这些特定的包代码文件。

总结说明

这个例子已经学习完了,虽然它比较简单,但是让我们清晰的了解如何使用AndroidTestRunner,后面我们将继续介绍一些复杂的例子,更加深入的学习。

你可能感兴趣的:(Android、JUnit深入浅出(五)——An…)