junit在android中的使用

来源:互联网 发布:神雕侠侣湖南卫视源码 编辑:程序博客网 时间:2024/06/07 06:14

Android Junit

Junit 是在Android SDK 1.5 中引入进来 。 

 

JUnit是采用测试驱动开发的方式,也就是说在开发前先写好测试代码,主要用来说明被测试的代码会被如何使用,错误处理等;然后开始写代码,并在测试代码中逐步测试这些代码,直到最后在测试代码中完全通过。

在开发中长使用Junit 可以让人养成良好的变成习惯,让你的代码更清晰,更独立,达到松耦合的目的。

 

Android SDK中包含的JUnit数据包功能说明:

•       junit.framework     JUnit测试框架

•       junit.runner   实用工具类支持JUnit测试框架

•       android.test   Android 对JUnit测试框架的扩展包

•       android.test.mock  Android的一些辅助类

•       android.test.suitebuilder 实用工具类,支持类的测试运行


Junit包结构

 


其中常用的assertEquals和assertSame方法有所不同

1)   提供的接口数量不完全相同。
assertEquals支持boolean,long,int等等java primitiveType变量。
assertSame只支持Object

2)   比较的逻辑不同,结果可能不同。
assertSame是对象直接比较。assertEquals能利用被比较对象提供的比较逻辑来进行比较。
使得同样的条件下,两者的运行结果不一定相同。
简单解释如下:
assertEquals(Object A,  Object B) 的比较逻辑:
如果 A,B都是Null,返回true。否则调用 A.equals(B)来判断。

assertSame(ObjectA, Object B)的比较逻辑:
以A == B运算的结果来判断。

A.equals(B)和 A==B 的差别在于。
如果A没有重写java.lang.Object的equals方法,
那么就是两个java对象的内存地址比较,比较结果和 A==B的结果相同。
如果A重写了equals方法(比如GregorianCalendar,BigDecimal类),
那么比较的结果不一定和A==B的结果相同

 

 

类的继承关系:

•       Test—TestCase—AndroidTestCase

•       Test—TestCase—InstrumentationTestCase

•       Test—TestSuite—InstrumentationTestSuite

•       TestListener——BaseTestRunner—AndroidTestRunner

•       Instrumentation—InstrumentationTestRunner

 

上面介绍了一些关于junit的结构和 继承关系,下面举例说明一下junit测试

 

代码如下

package aexp.junit;

 

import android.content.ContentResolver;

import android.content.ContentValues;

import android.database.Cursor;

import android.net.Uri;

import android.provider.Contacts;

import android.util.Log;

import android.test.AndroidTestCase;

 

 

//第一步,创建一个ContactTest类 该类继承AndroidTestCase 实现里面的setUp和 tearDown方法

//setUp方法是用来做一些数据的初始化,例如你在调用某个要测试的方法中需要一些对象//的初始化工作就可以在setUp方法中进行初始,tearDown方法是用类做资源释放的,当在//setUp方法中完的数据,就可以在tearDown中释放掉,在这个类里面 还有一些以test开都//的方法 例如:testInsertContact(), 这个方法就是你自己写的测试方法,我个人理解为在这个类中 方法执行的顺序是setUp -à testInsertContact-àtearDown 是这么个过程。

你自己写的测试方法一定要已test开头

public class ContactTest extendsAndroidTestCase

{

   static final String LOG_TAG = "ContactTest";

   static final String TESTUSER_NAME = "Test User";

   static final String TESTUSER_NOTES = "Test note";

   ContentResolver contentResolver;

   Uri newPerson;

 

   public void setUp()

    {

       contentResolver = getContext().getContentResolver();

       ContentValues person = new ContentValues();

       person.put(Contacts.People.NAME, TESTUSER_NAME );

       person.put(Contacts.People.NOTES, TESTUSER_NOTES );

 

       newPerson = contentResolver.insert(

                   Contacts.People.CONTENT_URI,person);

    }

 

   public void testInsertContact()

    {

       Log.d( LOG_TAG, "testInsertContact" );

       assertNotNull( newPerson );

    }

 

   public void testQueryContact()

    {

       Log.d( LOG_TAG, "testQueryContact" );

           String columns[] = { Contacts.People.NAME,

                           Contacts.People.NOTES };

       Cursor c = contentResolver.query( Contacts.People.CONTENT_URI,

                    columns,

                   Contacts.People.NAME+"=?",

                    new String[] {TESTUSER_NAME },

                    null );

       assertNotNull( c );

       int hits = 0;

       while( c.moveToNext() )

       {

           int nameColumnIndex = c.getColumnIndex( Contacts.People.NAME );

           int notesColumnIndex = c.getColumnIndex( Contacts.People.NOTES );

               String name = c.getString(nameColumnIndex );

           String notes = c.getString( notesColumnIndex );

           Log.d( LOG_TAG,"retrieved name: "+name );

           Log.d( LOG_TAG,"retrieved notes: "+notes );

           assertEquals( TESTUSER_NAME,name );

           assertEquals( TESTUSER_NOTES, notes );

           ++hits;

       }

       assertEquals( hits,1 );

       c.close();

    }

 

   public void tearDown()

    {

       contentResolver.delete( newPerson, null, null );

    }

}

 

//第二部,创建ExampleSuite类 继承TestSuite

 

 

package aexp.junit;

 

import junit.framework.TestSuite;

 

public class ExampleSuite extends TestSuite

{

   public ExampleSuite()

    {

       addTestSuite( MathTest.class );

       addTestSuite( ContactTest.class );

        addTestSuite(SomeTest.class);

    }

}

 

 

 

 

在这里说说TestSuite

自己定义的TestCase,并使用TestRunner来运行测试,事实上TestRunner并不直接运行 TestCase上的单元方法,而是透过TestSuite,TestSuite可以将数个TestCase在一起,而让每个TestCase保持简单。

来看看一个例子:

MathToolTest.java

package onlyfun.caterpillar.test;

 

import onlyfun.caterpillar.MathTool;

import junit.framework.TestCase;

 

public class MathToolTest extendsTestCase {

   public MathToolTest(String testMethod) {

       super(testMethod);

   }

 

   public void testGcd() {

       assertEquals(5, MathTool.gcd(10, 5));

   }

 

   public static void main(String[] args) {

       junit.textui.TestRunner.run(MathToolTest.class);

   }

}


在这个例子中,您并没有看到任何的TestSuite,事实上,如果您没有提供任何的TestSuite,TestRunner会自己建立一个,然後这个TestSuite会使用反射(reflection)自动找出testXXX()方法。

如果您要自行生成TestSuite,则在继承TestCase之後,提供静态的(static)的suite()方法,例如:

publicstatic Test suite() {
     return new TestSuite(MathTool.class);
}


如果您没有提供任何的TestSuite,则TestRunner就会像上面这样自动为您建立一个,并找出testXXX()方法,您也可以如下面定义 suite()方法:

publicstatic Test suite() {
     TestSuite suite = new TestSuite(MathTool.class);
     suite.addTest(new MathToolTest("testGcd"));
     return suite;
}

 
JUnit并没有规定您一定要使用testXXX()这样的方式来命名您的测试方法,如果您要提供自己的方法(当然JUnit 鼓励您使用testXXX()这样的方法名称),则可以如上撰写,为了要能够使用建构函式提供测试方法名称,您的TestCase必须提供如下的建构函 式:

publicMathToolTest(String testMethod) {
    super(testMethod);
}

 

如果要加入更多的测试方法,使用addTest()就可以了,suite()方法传回一个TestSuite物件,它与 TestCase都实作了Test介面,TestRunner会调用TestSuite上的run()方法,然後TestSuite会将之委托给 TestCase上的run()方法,并执行每一个testXXX()方法。

除了组合TestCase之外,您还可以将数个TestSuite组合在一起,例如:

publicstatic Test suite() { 
    TestSuite suite= new TestSuite(); 
    suite.addTestSuite(TestCase1.class);
    suite.addTestSuite(TestCase2.class); 
    return suite; 
}

 
如此之来,您可以一次运行所有的测试,而不必个别的运行每一个测试案例,您可以写一个运行全部测试的主测试,而在使用TestRunner时呼叫 suite()方法,例如:

junit.textui.TestRunner.run(TestAll.suite());


TestCase与TestSuite都实作了Test介面,其运行方式为 Command 模式 的一个实例,而TestSuite可以组合数个TestSuite或TestCase,这是 Composite 模式 的一个实例。

 

 

 

 

 

第三步,修改清单文件(AndroidManifest.xml)

如果你要使用Junit 并且是在eclipse中使用的话

就必须在AndroidManifest.xml中加上

<?xml version="1.0"encoding="utf-8"?>

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

      package="aexp.junit"

      android:versionCode="1"

      android:versionName="1.0.0">

    <uses-permissionandroid:name="android.permission.WRITE_CONTACTS"/>

    <uses-permissionandroid:name="android.permission.READ_CONTACTS"/>

    <application android:label="@string/app_name">

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

        <activityandroid:name=".JUnit"

                 android:label="@string/app_name">

            <intent-filter>

                <actionandroid:name="android.intent.action.MAIN" />

                <categoryandroid:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

  

 <instrumentationandroid:targetPackage="aexp.junit"android:name="android.test.InstrumentationTestRunner"

         android:label="AndroidJUnit测试" />

  <uses-sdk android:minSdkVersion="4" />

</manifest>

 

红色文字的地方是要加上的代码,注意instrumentationandroid:targetPackage指向的是你当前应用的包。

 

在附上一个关于activity的代码

 

package aexp.junit;

 

import android.app.Activity;

import android.os.Bundle;

import android.test.AndroidTestCase;

import android.test.AndroidTestRunner;

import android.widget.Button;

import android.widget.TextView;

import android.widget.Toast;

import android.view.View;

import android.util.Log;

import junit.framework.TestListener;

import junit.framework.Test;

importjunit.framework.AssertionFailedError;

 

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 stillrunning",

                       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,

                        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;

       }

 

       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 implementsRunnable,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 addFailure(Test test, AssertionFailedError t)

       {

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

       }

 

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

       }

}

 

 

这是个人简单的对android中 junit的一些使用上的理解。