====== android 单元测试介绍 ======
JUnit是一个开源的java单元测试框架,android的测试套件是基于JUnit 3的(不完全兼容JUnit 4),Junit4只需简单了解即可,可以使用普通的junit来进行测试,推荐使用android的Junit测试框架进行高效全面的进行测试。
====== Android 单元测试框架UML ======
{{:dolphin_news:share:androidjunituml.png?300 |}}
====== eclipse下的andriod项目单元测试 ======
使用AndroidJunit来做单元测试,大致可以分以下几个步骤:
- 新建Android Test Project
- 新建Junit test case
- 新建Junit test suite
- 运行Junit test
===== 新建 Android Test Project =====
这部分内容是在eclipse中导入了shell_en_aglie的基础上的完成的,请首先确保你已经成功导入了shell_en_agile工程(其它工程也是一样)。新建Android Test Project方法:
- 在eclipse中File->New->Other->Android->AndroidTestProject, 输入测试工程名, 如输入dolphin_junit_test。
- 下一步选择被测试的工程, 如选择测试DolphinBrowerEn, 这一步就完成了。
此时我们打开AndroidManifest.xml看一下
<code>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<!-- 此处包名被修改了,自动会根据被测项目生成为mobi.mgeek.TunnyBrower.test-->
package="com.dolphin.browser.core.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="mobi.mgeek.TunnyBrower" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:name="android.test.runner" />
</application>
</manifest>
</code>
可以看到, 已经自动生成了一些内容, 如uses-library和instrumentation已经自动生成了,这里需要注意一下包名,因为前面我们选择了被测试的工程为DolphinBrowerEn,所以这里的自动为我们指定了targetPackage="mobi.mgeek.TunnyBrowser", 并且为测试工程包名package="mobi.mgeek.TunnyBrowe.test",这里的包名因需要可以修改, 但targetPackage="com.dolphin.browser.core"为被测工程的包名,不能修改。
===== 新建 Junit Test Case =====
新建Junit Test Case方法:
- 在eclipse中File->New->Other->Junit->Junit Test Case
- 在弹出的Junit Test Case 对话框中选择New Junit 3 test,Superclass 选择AndroidTestCase,并选择 Class under test 被测试类,输入Name类名,点击下一步后。
- 选择需要被测试的方法,这里根据实际情况选择需要被测试的方法, 点击完成。
===== 新建 Junit Test Suite =====
新建 Junit Test Suite方法:
- 在eclipse中File->New->Other->Junit->Junit Test Suite
- 在弹出的Junit Test Case 对话框中选择需要测试的类。
- 选择需要被测试的方法,这里根据实际情况选择需要被测试的方法, 输入Name后点击完成。
- 编写TestSuite代码
- 编写TestSuite后, 需要在AndroidManifest中添加一项instrumentation, 添加后的AndroidManifest就变成了
<code>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dolphin.browser.core.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.dolphin.browser.core" />
<!-- 添加 testsuite 项 -->
<instrumentation
android:name="com.dolphin.browser.core.test.Testall"
android:targetPackage="com.dolphin.browser.core" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:name="android.test.runner" />
</application>
</manifest>
</code>
TestSuite代码完成后如下, 代码中使用了继承InstrumentationTestRunner,主要是通过addTestSuite来添加测试类,这里我只有一个测试类,当有多个测试类时,就可以把它们都加进去。
<code java>
public class TestAll extends InstrumentationTestRunner{
private static final String TAG = "TestAll";
public TestSuite getAllTests(){
Log.i(TAG, "Junit test, testsuite");
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(NewsRequestWrapperTest.class);
return suite;
}
}
</code>
===== 运行 Junit =====
可以参考 http://blog.csdn.net/xianming01/article/details/7463066 ,由于被测试工程较大, 在eclipse中导致不能通过图形化界面运行Junit,所以我们可以采用adb shell am 的方式运行生成的junit apk 来测试。具体方法是:
- 将被测apk安装到手机中
- 将junit程序生成后的apk安装到手机中
- 输入adb shell pm list instrumentation, 会显示类似以下信息,下面显示了有两个instruementation, 第一个test case, 第二个是test suite.
instrumentation:com.dolphin.browser.junittest/android.test.InstrumentationTestRunner (target=mobi.mgeek.TunnyBrowser)\\
instrumentation:com.dolphin.browser.junittest/.testall.TestAll (target=mobi.mgeek.TunnyBroer)
按链接中的说明, 可以输入adb shell am instrument -w com.dolphin.browser.junittest/android.test.InstrumentationTestRunner执行单条测试用例, 也可以
输入adb shell am instrument -w com.dolphin.browser.junittest/.testall.TestAll来执行test suite。
===== 注意事项 =====
- 创建工程时, 注意package 和 targetPackage 的关系。
- 由于我测试的是DolphinBrowserEn,在eclipse中无法编译,所以使用了生成测试apk,然后安装到手机中,使用adb shell am 方式进行测试。
- 如何写测试方法, 这里不做说明, 需要注意被测试方法为异步方法时,如http,需要用到线程同步去等待异步任务的完成。
- 我们也可以写一个activity,画一个简单的界面,通过点击button触发单元测试, 也可以对界面进行单元测试。
====== gradle环境下进行android单元测试方法一 ======
这部分内容以AOSP 里的development/samples/NotePad为例,NotePad工程下的单元测试代码在它的tests文件夹里。
步聚:
* 先新建一个文件夹testJunit(名字任意),将development/samples/NotePad项目复制到里面。
* 现在文件结构是 testJunit 里面是NotePad工程,工程下就是src, res, tests, AndroidManifest等。
* 在testJunit里新建三个文件,build.gradle, common.gradle, settings.gradle.
build.gradle 内容如下:
<code>
def gradle = project.getGradle()
gradle.beforeProject { project ->
if (project.file(‘build.gradle‘).exists()) {
project.buildscript {
repositories {
maven {
name = "Baina Maven Proxy"
url = "http://mirrors.baina.com:8080/archiva/repository/internal"
}
}
dependencies {
classpath ‘com.android.tools.build:gradle:0.6.+‘
}
}
}
}
</code>
common.gradle内容如下:
<code>
tasks.withType(JavaCompile) {
options.fork = true
options.forkOptions.setMemoryMaximumSize("4096m")
options.forkOptions.setMemoryInitialSize("1024m")
options.encoding = "UTF-8"
}
android {
compileSdkVersion 17
buildToolsVersion "18.0.1"
sourceSets {
main {
manifest.srcFile ‘AndroidManifest.xml‘
java.srcDirs = [‘src‘]
resources.srcDirs = [‘src‘]
aidl.srcDirs = [‘src‘]
renderscript.srcDirs = [‘src‘]
res.srcDirs = [‘res‘]
assets.srcDirs = [‘assets‘]
}
instrumentTest {
java.srcDirs = [‘tests/src‘]
resources.srcDirs = [‘tests/src‘]
aidl.srcDirs = [‘tests/src‘]
renderscript.srcDirs = [‘tests/src‘]
res.srcDirs = [‘tests/res‘]
assets.srcDirs = [‘tests/assets‘]
}
//instrumentTest.setRoot(‘tests‘)
}
}
</code>
此处instrumentTest也可以另一种方式写成
instrumentTest.setRoots(‘tests‘), 这样的话,需把NotePad里的src改为java, 为了在eclipse中能运行,建议采用分别指明目录的方式。
settings.gradle内容如下:
<code>
include ‘:NotePad‘
</code>
* 在NotePad 文件夹里新建build.gradle, 内容如下:
<code>
apply plugin: ‘android‘
apply from: "$project.rootDir/common.gradle"
android {
compileSdkVersion 16
buildTypes {
release {
runProguard true
proguardFile ‘proguard.cfg‘
}
debug {
runProguard true
proguardFile ‘proguard-debug.cfg‘
}
}
defaultConfig {
testPackageName "com.example.android.notepad.tests"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
}
}
}
</code>
说明:以上四个gradle文件我是从shell_en_agile里的复制过来的, 参考它的结构并修改而来的。
* 编译
在 testJunit 运行 gradle --daemon assembleDebug 会生成NotePad工程的apk, 运行 gradle --daemon assembleTest 会生成单元测试工程的apk。
* 运行
安装test apk, 运行 adb shell am instrument -w com.dolphin.browser.junittest/android.test.InstrumentationTestRunner。
====== gradle 环境下做android单元测试的配置方法二 ======
实现工作中,为了使tests工程与被测工程的git commit message相关不干扰,可以将单元测试独立出来管理,这样与被测工程相对独立,tests工程不会影响NotePad工程。在方法一的基础上继续下面的操作。
步聚:
* 将NotePad 里的 tests剪切出来放到NotePad 平行的位置, 现在文件结构是 testJunit 里有两个文件夹,NotePad 及tests, NotePad里面只剩下了src, res等。
* cd NotePad , 将测试工程通过软链接的方式链接进来: ln -s ../tests tests。
* 编译:
在testJunit下编译 gradle --deamon installTest, 编译完成后, 可以查看build下是否生成了对应的单测测试文件的class文件,确认编译没有问题。
* 运行:
参照测试工程tests, 具体命令可参考AOSP/development/samples/ApiDemos/tests 里的 AllTests.java。
To run all suites found in this apk: adb shell am instrument -w com.dolphin.browser.junittest/android.test.InstrumentationTestRunner \\
To run just this suite from the command line: adb shell am instrument -w -e class com.dolphin.browser.junittest.TestAll com.dolphin.browser.junittest/android.test.InstrumentationTestRunner \\
To run an individual test case: adb shell am instrument -w -e com.dolphin.browser.junittest.xxxtest com.dolphin.browser.junittest/android.test.InstrumentationTestRunner \\
To run an individual testcase: adb shell am instrument -w -e class com.dolphin.browser.junittest.news.test.NewsRequestWrapperTest com.dolphin.browser.junittest/android.test.InstrumentationTestRunner \\