2010年11月20日 星期六

Android、JUnit深入淺出(五)——AndroidTest例子分析

http://www.cnblogs.com/rockchip/articles/1746269.html

Android、JUnit深入淺出(五)——AndroidTest例子分析

前面我們學習了android.test包中的大部分類,是該通過學習具體的例子將前面的知識融會貫通,讓我們的理解更加深刻,例子程序代碼下載地址,下載後添加Eclipes的工程中,邊看這篇文章邊閱讀例子程序的代碼。
首先分析整個工程的結構圖,如下:


AndroidTestCase,Testsuite在前面的篇幅中已經學習過了,ContestTest、MathTest、SomeTest、ExampleSuite在前面的例子中已經為大家介紹了,這裡我們主要說明整個程序是如何運行的?
核心類代碼簡要列舉,如下:

public class JUnit 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 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類的函數。 這裡使用單獨線程的主要作用就是:testRunner.runTest();會佔用大量的時間,如果直接在UI線程中運行會阻滯UI線程,導致界面停止反應,這對用戶的操作會有很大的影響。
如何將TestRunner 中的測試信息顯示在界面上?

在前面的Snake例子程序中介紹過:Android SDK為我們提供了Handler,通過Handler與一個線程的消息隊列相關聯,發送和處理信息。 在這個例子中使用了Activity類的runOnUiThread (Runnable action)函數,這個函數的主要功能:在UI線程中運行指定的操作,如果當前線程是UI線程,然後採取行動立即執行;如果當前線程不是UI線程,發送消息到UI線程的事件隊列。

整個程序就介紹完了,運行程序後的界面如下:

在這裡需要特殊說明的是:打開AndroidManifest.xml文件,發現有個以前沒有見過的標記,如下:









user-library元素說明:指定一個共享庫,應用程序需要連接的。 默認情況下會連接所有的Android庫,然而一些軟件包(如地圖和AWT)是不會自動連接獨立的庫,以確定哪些庫需要包含這些特定的包代碼文件。
總結說明

這個例子已經學習完了,雖然它比較簡單,但是讓我們清晰的了解如何使用AndroidTestRunner,後面我們將繼續介紹一些複雜的例子,更加深入的學習。

沒有留言:

張貼留言