如何使用junit4写单元测试用例

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用junit4写单元测试用例相关的知识,希望对你有一定的参考价值。

Junit4支持注解了,只要在要执行的方法前加@Test即可,如:
@Test
public void multiplyPoundsByInteger()
assertEquals( 10, 5 );

Junit4增加了许多特性,主要是支持注解了:
测试由原来的命名模式改变注解,即testXXX变为@Test。其中@Test还提供了额外的属性。如expected,表示期望抛出的异常
数组比较改用Assert.assertArrayEquals
套件测试也用注解替换
通过@Ignore,可以忽略某个方法或整个类的测试
增加了新特性-理论机制(Theory),这个特性听起来很迷惑人,作用是使得开发人员从开始的定义测试用例的阶段就可以通过参数集(理论上是无限个参数)对代码行为进行概括性的总结.开发人员都知道他们代码所想要实现的概括性的总的目的,理论使得他们只需要在一个地方就可以快速的指定这些目的,而不要将这些目的翻译成大量的独立的测试用例。
提供了新的特性-假设机制(Assumption).此特性使用了Hamcrest库的类.本来Hamcrest是一个单独的测试组件,Junit也集成了一部分,但是并没有完全包含。建议使用junit独立的JAR文件,再单独引入hamcrest包。 其实hamcrest的功能相当的强大,理解起来也非常的容易,是一个很不错的组件。它提供assertThat,assumeThat,assumeNotNull等假设语句,也提供is,not,both..and,either..or等用法,非常的灵活。
@Before,@After,@BeforeClass,@AfterClass.这几个注解一看便知大概,@Before表示每个测试方法执行前执行一次,而@BeforeClass表示整个类测试前执行一次。不过需要注意的是,@BeforeClass,@AtferClass注解的方法必须是静态的。
Junit提供了新的核心运行类MaxCore,相对于以前的JunitCore运行机制,这个类有一系列的优点,如从未测试过的方法优先测试,剩下的测试中,以前测试失败的方法优先测试,再其次,运行快的优先于运行慢的方法。
参数化测试 允许通过变化范围的参数值来测试方法。
超时测试(Timeout test)可以被用来测试方法的执行时间。
Rule。它是JUnit4.7才开始提供的一种扩展方式,它能够替代大部分已有的Runner扩展。JUnit包含两种Rule Annotation:@ClassRule与@Rule。@ClassRule应用于测试类中的静态变量,而@Rule应用于成员变量;相同地是,这些变量必须是TestRule接口的实例,且访问修饰符必须为public。
参考技术A Junit4支持注解了,只要在要执行的方法前加@Test即可,如:
@Test
public void multiplyPoundsByInteger()
assertEquals( 10, 5 );

Junit4增加了许多特性,主要是支持注解了:
测试由原来的命名模式改变注解,即testXXX变为@Test。其中@Test还提供了额外的属性。如expected,表示期望抛出的异常
数组比较改用Assert.assertArrayEquals
套件测试也用注解替换
通过@Ignore,可以忽略某个方法或整个类的测试
增加了新特性-理论机制(Theory),这个特性听起来很迷惑人,作用是使得开发人员从开始的定义测试用例的阶段就可以通过参数集(理论上是无限个参数)对代码行为进行概括性的总结.开发人员都知道他们代码所想要实现的概括性的总的目的,理论使得他们只需要在一个地方就可以快速的指定这些目的,而不要将这些目的翻译成大量的独立的测试用例。
提供了新的特性-假设机制(Assumption).此特性使用了Hamcrest库的类.本来Hamcrest是一个单独的测试组件,Junit也集成了一部分,但是并没有完全包含。建议使用junit独立的JAR文件,再单独引入hamcrest包。 其实hamcrest的功能相当的强大,理解起来也非常的容易,是一个很不错的组件。它提供assertThat,assumeThat,assumeNotNull等假设语句,也提供is,not,both..and,either..or等用法,非常的灵活。
@Before,@After,@BeforeClass,@AfterClass.这几个注解一看便知大概,@Before表示每个测试方法执行前执行一次,而@BeforeClass表示整个类测试前执行一次。不过需要注意的是,@BeforeClass,@AtferClass注解的方法必须是静态的。
Junit提供了新的核心运行类MaxCore,相对于以前的JunitCore运行机制,这个类有一系列的优点,如从未测试过的方法优先测试,剩下的测试中,以前测试失败的方法优先测试,再其次,运行快的优先于运行慢的方法。

通过JUnit进行Android单元测试

 

 

要了解android单元测试,首先必须了解junit

什么是 JUnit ?

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

现简要说JUnit的4大功能

  1. 管理测试用例。修改了哪些代码,这些代码的修改会对哪些部分有影响,通过JUnit将这次的修改做个完整测试。这也就JUnit中所谓的TestSuite。
  2. 定义测试代码。这也就是JUnit中所谓的TestCase,根据源代码的测试需要定义每个TestCase,并将TestCase添加到相应的TestSuite方便管理。
  3. 定义测试环境。在TestCase测试前会先调用“环境”配置,在测试中使用,当然也可以在测试用例中直接定义测试环境。
  4. 检测测试结果。对于每种正常、异常情况下的测试,运行结果是什么、结果是否是我们预期的等都需要有个明确的定义,JUnit在这方面提供了强大的功能。

以上部分与我们平常使用IDE调试的过程是完全一样的,只不过是增加了测试用例管理、测试结果检测等功能,提高了单元的效率,保证了单元测试的完整性,明确了单元测试的目标。

 

JUnit 基本原理

一个 JUnit 测试包含以下元素:

表 1. 测试用例组成

开发代码部分 测试代码部分 测试工具部分
待测试类 A 通过扩展 TestCase 或者构造 TestSuit 方法
编写测试类 B
一个测试运行器(TestRunner)R,可以选择图形界面或文本界面

 

操作步骤:

将 B 通过命令行方式或图形界面选择方式传递给 R,R 自动运行测试,并显示结果。

首先看下junit测试类库和android中单元测试类库:

 

SDK 功能说明
junit.framework JUnit测试框架
junit.runner 实用工具类支持JUnit测试框架
android.test Android 对JUnit测试框架的扩展包
android.test.mock Android的一些辅助类
android.test.suitebuilder 实用工具类,支持类的测试运行

在这些包中最为重要的是: junit.framework、 android.test,其中前者是JUnit的核心包,后者是Andoid SDK在Junit.framework的基础上扩展出来的包,我们将重点解析这2个包。

junit.framework:

通过JUnit进行Android单元测试

 

 

  1. TestSuit:TestSuite是测试用例的集合;
  2. TestCase:定义运行多个测试用例;
  3. TestResult:收集一个测试案例的结果,测试结果分为失败和错误,如果未能预计的断言就是失败,错误就像一个ArrayIndexOutOfBoundsException异常而导致的无法预料的问题;
  4. TestFailure:测试失败时捕获的异常;
  5. Assert:断言的方法集,当断言失败时显示信息;

TestCase与TestSuite之间的关系,有些类似于图元对象与容器对象之间的关系

 

android.test包:

通过JUnit进行Android单元测试

 

JUnit TestCase类

继承自JUnit的TestCase,不能使用Instrumentation框架。但这些类包含访问系统对象(如Context)的方法。使用Context,你可以浏览资源,文件,数据库等等。基类是AndroidTestCase,一般常见的是它的子类,和特定组件关联。

子类有:

l   ApplicationTestCase——测试整个应用程序的类。它允许你注入一个模拟的Context到应用程序中,在应用程序启动之前初始化测试参数,并在应用程序结束之后销毁之前检查应用程序。

l   ProviderTestCase2——测试单个ContentProvider的类。因为它要求使用MockContentResolver,并注入一个IsolatedContext,因此Provider的测试是与OS孤立的。

l   ServiceTestCase——测试单个Service的类。你可以注入一个模拟的Context或模拟的Application(或者两者),或者让Android为你提供Context和MockApplication。

Instrumentation TestCase类

继承自JUnit TestCase类,并可以使用Instrumentation框架,用于测试Activity。使用Instrumentation,Android可以向程序发送事件来自动进行UI测试,并可以精确控制Activity的启动,监测Activity生命周期的状态。

基类是InstrumentationTestCase。它的所有子类都能发送按键或触摸事件给UI。子类还可以注入一个模拟的Intent。

子类有:

l   ActivityTestCase——Activity测试类的基类。

l   SingleLaunchActivityTestCase——测试单个Activity的类。它能触发一次setup()和tearDown(),而不是每个方法调用时都触发。如果你的测试方法都是针对同一个Activity的话,那就使用它吧。

l   SyncBaseInstrumentation——测试Content Provider同步性的类。它使用Instrumentation在启动测试同步性之前取消已经存在的同步对象。

l   ActivityUnitTestCase——对单个Activity进行单一测试的类。使用它,你可以注入模拟的Context或Application,或者两者。它用于对Activity进行单元测试。

不同于其它的Instrumentation类,这个测试类不能注入模拟的Intent。

l   ActivityInstrumentationTestCase2——在正常的系统环境中测试单个Activity的类。你不能注入一个模拟的Context,但你可以注入一个模拟的Intent。另外,你还可以在UI线程(应用程序的主线程)运行测试方法,并且可以给应用程序UI发送按键及触摸事件。

 

下面找了几个例子:

首先看junit,然后在看android test:

junit:

待测试类A:

 

package cn.edu.wtu.junit;

public class Calcuator {
    public double add(double n1, double n2) {
        return n1 + n1;
    }
}


测试代码B:扩展testcase

 

 

package cn.edu.wtu.junit;

import junit.framework.TestCase;

public class TestCalcuator extends TestCase {
    public void testAdd(){
        Calcuator calcuator=new Calcuator();
        double result=calcuator.add(1,2);
        assertEquals(3,result,0);
    }

}
testsuit 测试容器:
package cn.edu.wtu.junit;

import junit.framework.Test;
import junit.framework.TestSuite;
import junit.textui.TestRunner;

public class TestAll extends TestSuite {
    public static Test suite() {
        TestSuite suite = new TestSuite("TestSuite Test");
        suite.addTestSuite(TestCalcuator.class);
        suite.addTestSuite(TestCalcuator2.class);
        return suite;
    }
    public static void main(String args[]){
//    	命令行输出 测试工具 一个测试运行器
        TestRunner.run(suite());
    }
}


run on junit 图形界面显示:

 

通过JUnit进行Android单元测试

run java application:控制台输出:

通过JUnit进行Android单元测试

android test :

首先看下非instrumentation框架测试:

测试代码:

package aexp.junit;

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

 

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;

public class ContactTest extends AndroidTestCase 
{
    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 );
    }
}


子树:

 

 

package aexp.junit;

import junit.framework.TestSuite;
import junit.framework.Assert;

public class SomeTest extends TestSuite {
	public void testSomething() throws Throwable
	{
	       Assert.assertTrue(1 + 1 == 2);
	}

	public void testSomethingElse() throws Throwable
	{
	       Assert.assertTrue(1 + 1 == 3);
	}
}


测试树:

 

 

package aexp.junit;

import junit.framework.TestSuite;

public class ExampleSuite extends TestSuite
{
    public ExampleSuite() 
    {
        addTestSuite( MathTest.class );
        addTestSuite( ContactTest.class );
        addTestSuite(SomeTest.class);
    }
}


测试运行器:

 

 

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;
import junit.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 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 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 );
	        }
}

运行结果:

 

通过JUnit进行Android单元测试

 

instrumentation框架:

首先新建一个android工程:

里面编写3个activity:MainActivity,HomeActivity,LoginActivity

MainActivity是加载界面,LoginActivity是登陆界面,HomeActivity是最终界面

 

package cn.edu.wtu.junit;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity {
	
	private static final boolean DEBUG = true;
	private static final String TAG = "-- MainActivity";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		if (DEBUG) {
			Log.i(TAG, "onCreate");
		}

		super.onCreate(savedInstanceState);
		setContentView(R.layout.act_main);
		View toLoginView = findViewById(R.id.to_login);
		toLoginView.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				if (DEBUG) {
					Log.i(TAG, "toLoginView clicked");
				}

				Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
				startActivity(intent);
			}
		});
	}
}

 

package cn.edu.wtu.junit;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;

public class LoginActivity extends Activity {
	private static final boolean DEBUG = true;
	private static final String TAG = "-- LoginActivity";

	private EditText mUsernameView;
	private EditText mPasswordView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		if (DEBUG) {
			Log.i(TAG, "onCreate");
		}

		super.onCreate(savedInstanceState);
		setContentView(R.layout.act_login);
		mUsernameView = (EditText) findViewById(R.id.username);
		mPasswordView = (EditText) findViewById(R.id.password);

		View submitView = findViewById(R.id.submit);
		submitView.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				if (DEBUG) {
					Log.i(TAG, "submitView clicked");
				}

				Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
				intent.putExtra(HomeActivity.EXTRA_USERNAME, mUsernameView.getText().toString());
				intent.putExtra(HomeActivity.EXTRA_PASSWORD, mPasswordView.getText().toString());
				startActivity(intent);
			}
		});

		View resetView = findViewById(R.id.reset);
		resetView.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				if (DEBUG) {
					Log.i(TAG, "resetView clicked");
				}

				mUsernameView.setText("");
				mPasswordView.setText("");
				mUsernameView.requestFocus();
			}
		});
	}
}

 

package cn.edu.wtu.junit;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class HomeActivity extends Activity {
	private static final boolean DEBUG = true;
	private static final String TAG = "-- HomeActivity";

	public static final String EXTRA_USERNAME = "yuan.activity.username";
	public static final String EXTRA_PASSWORD = "yuan.activity.password";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		if (DEBUG) {
			Log.i(TAG, "onCreate");
		}
		super.onCreate(savedInstanceState);
		Intent intent = getIntent();
		StringBuilder sb = new StringBuilder();
		sb.append("username:").append(intent.getStringExtra(EXTRA_USERNAME)).append("\\n");
		sb.append("password:").append(intent.getStringExtra(EXTRA_PASSWORD));

		setContentView(R.layout.act_home);
		TextView loginContentView = (TextView) findViewById(R.id.login_content);
		loginContentView.setText(sb.toString());
	}
}


然后新建一个测试工程,基于上面一个project:

 

 

package cn.edu.wtu.test;

import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import android.view.View;
import cn.edu.wtu.junit.MainActivity;

public class MainActivityTest extends ActivityInstrumentationTestCase2
   
   
   
   
   
    
    
    
    
     {
	private static final String TAG = "=== MainActivityTest";

	private Instrumentation mInstrument;
	private MainActivity mActivity;
	private View mToLoginView;

	public MainActivityTest() {
		super("cn.edu.wtu.junit", MainActivity.class);
	}

	@Override
	public void setUp() throws Exception {
		super.setUp();
		mInstrument = getInstrumentation();
		// 启动被测试的Activity
		mActivity = getActivity();
		mToLoginView = mActivity.findViewById(cn.edu.wtu.junit.R.id.to_login);
	}

	public void testPreConditions() {
		// 在执行测试之前,确保程序的重要对象已被初始化
		assertTrue(mToLoginView != null);
	}


	
//	@UiThreadTest
//	这将会在UI线程里运行方法里所有的语句。不与UI交互的方法不允许这么做
//	注意:waitForIdleSync和sendKeys不允许在UI线程里运行
	public void testToLogin() {
		// @UiThreadTest注解使整个方法在UI线程上执行,等同于上面注解掉的代码

//		exception
		mInstrument.runOnMainSync(new Runnable() {
			public void run() {
				mToLoginView.requestFocus();
				mToLoginView.performClick();
			}
		});
		
//		mActivity.runOnUiThread(new Runnable(){
//
//			@Override
//			public void run() {
//				
//				mToLoginView.requestFocus();
//				mToLoginView.performClick();
//			}
//			
//		});
	}

	@Suppress
	public void testNotCalled() {
		// 使用了@Suppress注解的方法不会被测试
		Log.i(TAG, "method \'testNotCalled\' is called");
	}

	@Override
	public void tearDown() throws Exception {
		super.tearDown();
	}
}
   
   
   
   
   

 

package cn.edu.wtu.test;

import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import cn.edu.wtu.junit.LoginActivity;

public class LoginActivityTest extends ActivityInstrumentationTestCase2
   
   
   
   
   
    
    
    
    
     {
	private static final String TAG = "=== LoginActivityTest";

	private Instrumentation mInstrument;
	private LoginActivity mActivity;
	private EditText mUsernameView;
	private EditText mPasswordView;
	private View mSubmitView;
	private View mResetView;

	public LoginActivityTest() {
		super("cn.edu.wtu.junit", LoginActivity.class);
	}

	@Override
	public void setUp() throws Exception {
		super.setUp();
		/*
		 * 关闭触屏模式为了控制从测试程序中发送给模拟器或设备的按键事件,你必须关闭触屏模式。如果你不这么做,按键事件将被忽略。
		 * 你需要在调用getActivity()启动Activity之前调用ActivityInstrumentationTestCase2.setActivityTouchMode(false)。
		 * 你必须在非UI线程中运行这个调用。基于这个原因,你不能在声明有@UIThread的测试方法调用。可以在setUp()中调用。
		 * 要向程序发送key事件的话,必须在getActivity之前调用该方法来关闭touch模式
		 * 否则key事件会被忽略
		 */
		setActivityInitialTouchMode(false);

		mInstrument = getInstrumentation();
		mActivity = getActivity();
		Log.i(TAG, "current activity: " + mActivity.getClass().getName());
		mUsernameView = (EditText) mActivity.findViewById(cn.edu.wtu.junit.R.id.username);
		mPasswordView = (EditText) mActivity.findViewById(cn.edu.wtu.junit.R.id.password);
		mSubmitView = mActivity.findViewById(cn.edu.wtu.junit.R.id.submit);
		mResetView = mActivity.findViewById(cn.edu.wtu.junit.R.id.reset);
	}

	public void testPreConditions() {
		assertTrue(mUsernameView != null);
		assertTrue(mPasswordView != null);
		assertTrue(mSubmitView != null);
		assertTrue(mResetView != null);
	}

	public void testInput() {
		input();
		assertEquals("yuan", mUsernameView.getText().toString());
		assertEquals("1123", mPasswordView.getText().toString());
	}

	public void testSubmit() {
		input();
		mInstrument.runOnMainSync(new Runnable() {
			public void run() {
				mSubmitView.requestFocus();
				mSubmitView.performClick();
			}
		});
	}

	public void testReset() {
		input();
		mInstrument.runOnMainSync(new Runnable() {
			public void run() {
				mResetView.requestFocus();
				mResetView.performClick();
			}
		});
		assertEquals("", mUsernameView.getText().toString());
		assertEquals("", mPasswordView.getText().toString());
	}

	@Override
	public void tearDown() throws Exception {
		super.tearDown();
	}

	private void input() {
		mActivity.runOnUiThread(new Runnable() {
			public void run() {
				mUsernameView.requestFocus();
			}
		});
		// 因为测试用例运行在单独的线程上,这里最好要
		// 同步application,等待其执行完后再运行
		mInstrument.waitForIdleSync();
		sendKeys(KeyEvent.KEYCODE_Y, KeyEvent.KEYCODE_U,
				KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_N);

		// 效果同上面sendKeys之前的代码
		mInstrument.runOnMainSync(new Runnable() {
			public void run() {
				mPasswordView.requestFocus();
			}
		});
		sendKeys(KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_1,
				KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_3);
	}
}
   
   
   
   
   

 

package cn.edu.wtu.test;

import android.content.Intent;
import android.test.ActivityUnitTestCase;
import android.widget.TextView;
import cn.edu.wtu.junit.HomeActivity;

public class HomeActivityTest extends ActivityUnitTestCase
   
   
   
   
   
    
    
    
    
     {
	private static final String TAG = "=== HomeActivityTest";

	private static final String LOGIN_CONTENT = "username:yuan\\npassword:1123";

	private HomeActivity mHomeActivity;
	private TextView mLoginContentView;

	public HomeActivityTest() {
		super(HomeActivity.class);
	}

	@Override
	public void setUp() throws Exception {
		super.setUp();
		Intent intent = new Intent();
		intent.putExtra(HomeActivity.EXTRA_USERNAME, "yuan");
		intent.putExtra(HomeActivity.EXTRA_PASSWORD, "1123");
		// HomeActivity有extra参数,所以我们需要以intent来启动它
		mHomeActivity = launchActivityWithIntent("cn.edu.wtu.junit", HomeActivity.class, intent);
		mLoginContentView = (TextView) mHomeActivity.findViewById(cn.edu.wtu.junit.R.id.login_content);
	}

	public void testLoginContent() {
		assertEquals(LOGIN_CONTENT, mLoginContentView.getText().toString());
	}

	@Override
	public void tearDown() throws Exception {
		super.tearDown();
	}
}
   
   
   
   
   


run on android unit:

 

通过JUnit进行Android单元测试

 

参考:

http://www.ibm.com/developerworks/cn/java/j-lo-junit-src/

http://www.moandroid.com/?page_id=1176

http://www.ibm.com/developerworks/cn/java/j-lo-junit4/

http://www.cnblogs.com/xirihanlin/archive/2010/06/15/1758677.html

转:http://www.open-open.com/lib/view/open1328152424546.html

以上是关于如何使用junit4写单元测试用例的主要内容,如果未能解决你的问题,请参考以下文章

Spring-test + Junit4单元测试

在Maven项目中运行JUnit 5测试用例

8智能化单元测试框架实战

灵魂拷问:到底要不要写单元测试,如何正确进行单元测试?

灵魂拷问:到底要不要写单元测试,如何正确进行单元测试?

-单元测试框架-Junit