Android Junit基础知识

  http://blog.chinaunix.net/u/20947/showart_1950609.html

如果想在android里面做单元测试,有以下三种方法可行。

第一,  就是java程序员最为熟悉和常用的JUnit, android sdk如果用JUnit的话,我们需要在运行单元测试时,一定要 用JDK来运行,利用java命令来启动JUnit的某个Runner。如果是用Eclipse的话,可以在Run Configuration里新建一个JUnit。但是一定要记得在Classpath选项卡里将Bootstrap Entries中的Android Library改成JRE,并且添加junit.jar。具体的设置可以参考:http://developer.android.com/guide/appendix/faq/troubleshooting.html#addjunit。 而且,更为遗憾的是,这种方法运行的JUnit运行在JDK之上的,而不是android,所以,只能测试一些和android无关的东西,比如业务逻辑,数据封装,数值计算等等。并不能测试android api

第二,  采用Instrumentation. Android单元测试的主入口是InstrumentationTestRunner。它相当于JUnit当中TestRunner的作用。你可以将Instrumentation理解为一种没有图形界面的,具有启动能力的,用于监控其他类(用Target Package声明)的工具类。任何想成为Instrumentation的类必须继承android.app.Instrumentation。

第三,利用android提供的androidTestCase,通过继承这个类来实现自己的test case,然后自己为test设计UI,该方法具体用法放在了另外一篇博客中,可以点击下面的链接阅读:

 

下面通过一个实例来看一下如何通过Instrumentation来做单元测试。

Step 1. 首先编写需要测试的activity:


de>package com.android.ut;

import android.app.Activity;
import android.os.Bundle;

public class AndroidUT extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    public int add(int a, int b)
    {
        return a + b;
    }
}
de>


Step 2. 

接下来编写测试类,其中主要来测试add()方法。我们在当前代码目录下,在新建一个文件夹,命名为test,并在里面新建了包com.android.ut.test。然后往里面新增加一个class.具体如下:



de>package com.android.ut.test;

import com.android.ut.AndroidUT;

import android.test.ActivityInstrumentationTestCase;

public class TestApp extends ActivityInstrumentationTestCase<AndroidUT> {
    
    public TestApp()
    {
        super("com.android.ut", AndroidUT.class);
    }
    
    public void testSum()
    {
        assertEquals(5, getActivity().add(2, 3));
    }
    
}
de>



Step 3.最后一步就是要改一下Manifest文件。

de><?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.ut"
      android:versionCode="1"
      android:versionName="1.0.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".AndroidUT"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    <uses-library android:name="android.test.runner" />
    </application>
    <instrumentation android:targetPackage="com.android.ut" android:name="android.test.InstrumentationTestRunner" android:label="Test Unit Tests"></instrumentation>
</manifest>
de>



需要注意的是,在这里面我加上了:

    <uses-library android:name="android.test.runner" />

以及:

<instrumentation android:targetPackage="com.android.ut" android:name="android.test.InstrumentationTestRunner" android:label="Test Unit Tests"></instrumentation>

 

Step 4. 运行

首先通过模拟器运行一下AndroidUT,然后在命令行终端中运行

 adb shell am instrument -e class com.android.ut.test.TestApp -w com.android.ut/android.test.InstrumentationTestRunner

这样你就可以看到测试结果了。



通过AndroidTestCase来进行android 单元测试 part I

以前的博客中介绍过了如何用intrumentation进行android单元测试,其实还有一种方法同样可以,那就是利用AndroidTestCase来做单元测试,intrumentationTestCase和AndroidTestCase都是Junit.framwork.TestCase的子类,二者代表不用的方向。

 

如果想通过AndroidTestCase,大致可以通过以下几个步骤实现:

1.       添加自己的test case code, 让他们继承自AndroidTestCase。

2.       定义自己的testSuite类,用来管理test cases.

3.       定义自己的testRunner,用来执行测试

下面首先来看一下这种方法所涉及到的android的类以及接口。

AndroidTestCase

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 (in package junit.package)

一个de>TestSuitede>de>就是一系列de>de>test casede>de>的集合。通过de>de>testsuitede>de>可以更好的来管理de>de>test casede>

 

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); 
 

TestListener (in package junit.framework)

 

这是一个 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.

AndroidTestRunner

继承自class junit.runner.BaseTestRunner,但是它没有提供ui, 甚至来一个基于console的UI都没有,所以,如果想要很好的查看测试结果的话,你需要自己来处理来自于test runner的callback 函数。一会可以通过例子演示一下

AndroidTestRunner主要方法:

SetTest();

runTest()

addTestListener()

setContext()

如果要使用AndroidTestRunner,需要在permission in manifest.xml中添加权限:

<uses-library android:name="android.test.runner" />

最后,通过一个实例来演示一下:

1.       写一个test case:

MathTest.java


de>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" );
    }
}de>


2.  定义一个test suite类。

ExampleSuite.java




de>package com.ut.prac;

import junit.framework.TestSuite;

public class ExampleSuite extends TestSuite {
    public ExampleSuite() {
        addTestSuite( MathTest.class );
    }
}de>



3.  定义test runner,以及构建UI来处理测试流程,查看测试结果等。

MyJUnitExample.java


de>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 );
        }
}
de>



4.       最后是xml文件

Manifest.xml



de><?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>
de>


Mail.xml



de><?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>

de>

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值