创建测试工程:

测试工程通常都不是独立存在的,而是依赖于某个现有工程的,一般比较常见的做法是在现有工程下新建一个test文件夹,测试工程就存放在这里。

此处以BroadcastBestPractice这个项目为例 这里是项目

在Eclipse的导航栏中点击File->New->Other,会打开一个对话框。展开Android目录,在里面选中AndroidTestProject。



点击Next后会弹出创建Android测试工程的对话框,在这里我们可以输入测试工程的名字,并选择测试工程的路径



选择测试哪一个项目


点击Finish即可完成


此时观察测试工程中的AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcastbestpractice.test"
    android:versionCode="1"
    android:versionName="1.0" >

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

    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.example.broadcastbestpractice" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <span style="color:#ff0000;"><uses-library android:name="android.test.runner" /></span>
    </application>

</manifest>



<instrumentation>和<uses-library>标签是自动生成的,表示这是一个测试工程

在<instrumentation>标签中还通过android:targetPackage属性指定了测试目标的包名


下面进行单元测试

单元测试是指对软件中最小的功能模块进行测试,如果软件中的每一个单元都能通过测试,说明代码的健壮性就已经非常好了

BroadcaseBestPractice项目中有一个ActivityCollector类,主要用于对所有的Activity进行管理

public class ActivityCollector {
	
	public static List<Activity> activities = new ArrayList<Activity>();
	
	public static void addActivity(Activity activity) {
		activities.add(activity);
	}
	
	public static void removeActivity(Activity activity) {
		activities.remove(activity);
	}
	
	public static void finishAll() {
		for (Activity activity : activities) {
			if (!activity.isFinishing()) {
				activity.finish();
			}
		}
	}
	
}



我们来测试这个类


首先在BroadcastBestPracticeTest项目中新建一个ActivityCollectorTest类,并让它继承自AndroidTestCase,并重写setUp()和tearDown()方法

public class ActivityCollectorTest extends AndroidTestCase {
	
	@Override
	protected void setUp() throws Exception {
		super.setUp();
	}
	
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
	}
	
}





其中setUp()方法会在所有的测试用例执行之前调用,可以在这里进行一些初始化操作。

tearDown()方法会在所有的测试用例执行之后调用,可以在这里进行一些资源释放的操作。


一般来说,编写测试用例,只需要定义一个以test开头的方法,测试框架就会自动调用这个方法了

然后我们在方法中可以通过断言(assert)的形式来期望一个运行结果,再和实际的运行结果进行对比


比如测试ActivityCollector中的addActivity()方法:

public class ActivityCollectorTest extends AndroidTestCase {
	
	@Override
	protected void setUp() throws Exception {
		super.setUp();
	}
	
	public void testAddActivity() {
		assertEquals(0, ActivityCollector.activities.size());
		LoginActivity loginActivity = new LoginActivity();
		ActivityCollector.addActivity(loginActivity);
		assertEquals(1, ActivityCollector.activities.size());
	}
	
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
	}
	
}



这里我们添加了一个testAddActivity()方法

使用assertEquals()方法进行断言


右击测试工程->Run As->Android JUnit Test 来运行这个测试用例


测试结果通过


我们再添加一些特殊情况下的断言

public class ActivityCollectorTest extends AndroidTestCase {
	
	@Override
	protected void setUp() throws Exception {
		super.setUp();
	}
	
	public void testAddActivity() {
		assertEquals(0, ActivityCollector.activities.size());
		LoginActivity loginActivity = new LoginActivity();
		ActivityCollector.addActivity(loginActivity);
		assertEquals(1, ActivityCollector.activities.size());
		ActivityCollector.addActivity(loginActivity);
		assertEquals(1, ActivityCollector.activities.size());
	}
	
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
	}
	
}



这里添加了两次相同活动的实例

用于测试ActivityCollector是否有能力过滤掉重复的数据




很遗憾,测试用例并没有通过

提示我们期望结果是1,但实际结果却是2


可以发现addActivity()方法中的代码是不够健壮的


修改ActivityCollector中的代码

public class ActivityCollector {
	
	public static List<Activity> activities = new ArrayList<Activity>();
	
	public static void addActivity(Activity activity) {
		if (!activities.contains(activity)) {
			activities.add(activity);
		}
	}
	
	public static void removeActivity(Activity activity) {
		activities.remove(activity);
	}
	
	public static void finishAll() {
		for (Activity activity : activities) {
			if (!activity.isFinishing()) {
				activity.finish();
			}
		}
	}
	
}


再跑一遍测试用例


成功通过