Android CTS 测试研究之三
作者: 宋立新
Email : zjujoe@yahoo.com
前言
前面都是研究 CTS 面上的东西, 这两天认真学习了一下 Android Instrumentation Test 的相关内容,深切体会到其强大的功能!( UI 控制,生命周期控制,伪环境对象提供等等), 回过头来,我们再来看看 CTS 的细节内容。
和前面的内容区分开,我们从具体测试用例的角度来看。
首先选择文档中经常提起的 apidemo 作为研究对象。
例子一: apidemo
从 test plan 开始研究
~/mydroid/out/host/linux-x86/cts/android-cts/repository/plans$ cat CTS.xml
<?xml version="1.0" encoding="UTF-8"?>
<TestPlan version="1.0">
<Entry uri="android.apidemos.cts"/>
<Entry uri="android.accessibilityservice"/>
。。。
<Entry uri="android.core.vm-tests"/>
<Entry uri="android.tests.appsecurity"/>
</TestPlan>
可见,某个 test plan 只需要包括一个到具体测试用例的 uri 申明即可。
该 uri 的定义在 test cases 子目录下:
~/mydroid/out/host/linux-x86/cts/android-cts/repository/testcases$ cat ApiDemosReferenceTest.xml
<?xml version="1.0" encoding="UTF-8"?>
<TestPackage AndroidFramework="Android 1.0" apkToTestName="ApiDemos" appNameSpace="android.apidemos.cts" appPackageName="android.apidemos.cts" jarPath="" name="ApiDemosReferenceTest" packageToTest="com.example.android.apis" referenceAppTest="true" runner="android.test.InstrumentationTestRunner" targetBinaryName="" targetNameSpace="" version="1.0">
<TestSuite name="android">
<TestSuite name="apidemos">
<TestSuite name="cts">
<TestCase name="ApiDemosTest">
<Test name="testNumberOfItemsInListView"/>
</TestCase>
</TestSuite>
</TestSuite>
</TestSuite>
</TestPackage>
可见 , CTS 在 Android 的 Instrumentation Test 上又包了一层。该 xml 文件的格式说明没有找到,只能先望文生义了。
照字面理解,它要测试 ApiDemo, 测试的代码是 ApiDemoReferenceTest, 使用的 Test runner 是: android.test.InstrumentationTestRunner. ( 其它的 test runner 还有: android.test.InstrumentationCtsTestRunner, android.test.InstrumentationCoreTestRunner)
该 Test 一共只有一个 test: testNumberOfItemsInListView
以下是相关文件:
songlixin@zjujoe-desktop:~/mydroid/out/host/linux-x86/cts/android-cts/repository/testcases$ ls -l ApiDemo*
-rw-r--r-- 1 songlixin songlixin 2106161 2010-06-16 09:38 ApiDemos.apk
-rw-r--r-- 1 songlixin songlixin 5526 2010-06-16 09:38 ApiDemosReferenceTest.apk
-rw-r--r-- 1 songlixin songlixin 657 2010-06-16 09:38 ApiDemosReferenceTest.xml
现在看看这些位于 out 目录下的文件是如何生成的。
再看源码树
根据参考, 要在 cts 中添加一个 test package, 必须将其加入: build/core/tasks/cts.mk.
查看一下,果然 , 其中包含:
ApiDemos /
ApiDemosReferenceTest /
ApiDemos 位于:
~/mydroid/development/samples/ApiDemos$ tree -L 2
.
├── AndroidManifest.xml
├── Android.mk
├── assets
│ ├── fonts
│ └── read_asset.txt
├── _index.html
├── res
│ ├── anim
│ ├── drawable
。。。
│ ├── layout
│ ├── menu
│ ├── raw
│ ├── values
。。。
│ └── xml
├── src
│ └── com
└── tests
├── AndroidManifest.xml
├── Android.mk
├── build.properties
└── src
其中, make file 中包含 tests tag:
LOCAL_MODULE_TAGS := samples tests
ApiDemosReferenceTest 位于:
~/mydroid/cts/tests/ApiDemosReferenceTest$ tree
.
├── AndroidManifest.xml
├── Android.mk
└── src
└── android
└── apidemos
└── cts
├── AllTests.java
└── ApiDemosTest.java
其 make file 没有包含 tests tag, 但是父目录的 Android.mk 中包含了。并且它使用所有子目录的源码。
两个疑问
1) ApiDemosReferenceTest.xml 是从哪里来的?
猜测: 从 /mydroid/cts/tests/ApiDemosReferenceTest 生成
2) ApiDemosReferenceTest 中提供了两个 testcase, 而 ApiDemosReferenceTest.xml 只用了一个?
从代码上看, ~/mydroid/cts/tools/utilsbuildCts.py 是用来生成 test description 以及 test plan 的。它在 ~/mydroid/build/core/tasks/cts.mk 中被调用。
例子二: CtsExample
CTS test plan 中有:
<Entry uri="android.example"/>
这对应:
~/mydroid/out/host/linux-x86/cts/android-cts/repository/testcases$ ls -l CtsExampleTestCases.*
-rw-r--r-- 1 songlixin songlixin 3294 2010-06-16 10:58 CtsExampleTestCases.apk
-rw-r--r-- 1 songlixin songlixin 1257 2010-06-16 10:59 CtsExampleTestCases.xml
看它的 xml 文件:
<?xml version="1.0" encoding="UTF-8"?><TestPackage AndroidFramework="Android 1.0" appNameSpace="com.android.cts.example" appPackageName="android.example " name="CtsExampleTestCases" runner="android.test.InstrumentationTestRunner" version="1.0">
<TestSuite name="android">
<TestSuite name="example">
<TestSuite name="cts">
<TestCase name="ExampleTest">
<Test name="testBlort">
<Description> Test {@link Example#blort}. </Description>
</Test>
</TestCase>
<TestCase name="ExampleSecondaryTest">
<Test name="testZorch">
<Description> Test {@link Example#zorch}. </Description>
</Test>
</TestCase>
</TestSuite>
</TestSuite>
</TestSuite>
</TestPackage>
其中包含了两个 test case.
我们再看 build/core/tasks/cts.mk :
CtsExampleTestCases /
该 package 位于:
~/mydroid/cts/tests/tests/example$ tree
.
├── AndroidManifest.xml
├── Android.mk
└── src
└── android
└── example
├── cts
│ ├── ExampleSecondaryTest.java
│ └── ExampleTest.java
└── Example.java
该 package 的特殊之处在于它的测试代码以及被测试代码都在同一个包内。
两个 TestCase 都是从 TestCase 继承,因为它不需要更复杂的功能。
可以发现, 相比较 ApiDemo 而言,这是一个更典型的 CTS 测试的例子。如果您想写自己的 cts 测试用例,不凡模仿它。更进一步说, cts/tes/tests 下的那些例子更适合我们用来参考。比如: performance 目录下的 MultiAppStartupTest, 继承了 InstrumentationTestCase. 也是一个很好的例子。
另外,还发现每个例子其包的最后一段总是 cts, 不知是不是硬性要求。这也可以说明 CTS 是基于 instrumentation test, 但是又不等同。
疑问
AndroidManifest.xml 中定义的 package name 为: com.andoid.cts.example
Example 类属于:
package android.example;
public class Example
ExampleTest 类属于:
package android.example.cts;
public class ExampleTest extends TestCase
非常奇怪!
单个运行 CTS 测试用例
安装
~/mydroid/out/host/linux-x86/cts/android-cts/repository/testcases$ adb install CtsPerformanceTestCases.apk
70 KB/s (4518 bytes in 0.062s)
pkg: /data/local/tmp/CtsPerformanceTestCases.apk
Success
查看一下已经安装的 instrumentation
~/mydroid/out/host/linux-x86/cts/android-cts/repository/testcases$ adb shell pm list instrumentation
instrumentation:com.android.cts.performance/android.test.InstrumentationTestRunner (target=com.android.calculator2)
instrumentation:com.android.example.spinner.test/android.test.InstrumentationTestRunner (target=com.android.example.spinner)
instrumentation:com.example.android.apis/.app.LocalSampleInstrumentation (target=com.example.android.apis)
instrumentation:com.example.helloandroid.test/android.test.InstrumentationTestRunner (target=com.example.helloandroid)
运行(失败)
:~/mydroid/out/host/linux-x86/cts/android-cts/repository/testcases$ adb shell am instrument -w -r com.android.cts.performance/android.test.InstrumentationTestRunner
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: current=1
INSTRUMENTATION_STATUS: class=android.performance.cts.MultiAppStartupTest
INSTRUMENTATION_STATUS: stream=
android.performance.cts.MultiAppStartupTest:
INSTRUMENTATION_STATUS: numtests=1
INSTRUMENTATION_STATUS: test=testMultipleApps
INSTRUMENTATION_STATUS_CODE: 1
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: current=1
INSTRUMENTATION_STATUS: class=android.performance.cts.MultiAppStartupTest
INSTRUMENTATION_STATUS: stream=
Error in testMultipleApps:
android.content.ActivityNotFoundException: Unable to find explicit activity class {com.android.calendar/com.android.calendar.LaunchActivity}; have you declared this activity in your AndroidManifest.xml?
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1404)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1378)
at android.app.ApplicationContext.startActivity(ApplicationContext.java:555)
at android.performance.cts.MultiAppStartupTest.launchActivity(MultiAppStartupTest.java:52)
at android.performance.cts.MultiAppStartupTest.testMultipleApps(MultiAppStartupTest.java:89)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:205)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:195)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:430)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
INSTRUMENTATION_STATUS: numtests=1
INSTRUMENTATION_STATUS: stack=android.content.ActivityNotFoundException: Unable to find explicit activity class {com.android.calendar/com.android.calendar.LaunchActivity}; have you declared this activity in your AndroidManifest.xml?
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1404)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1378)
at android.app.ApplicationContext.startActivity(ApplicationContext.java:555)
at android.performance.cts.MultiAppStartupTest.launchActivity(MultiAppStartupTest.java:52)
at android.performance.cts.MultiAppStartupTest.testMultipleApps(MultiAppStartupTest.java:89)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:205)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:195)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:430)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
INSTRUMENTATION_STATUS: test=testMultipleApps
INSTRUMENTATION_STATUS_CODE: -1
INSTRUMENTATION_RESULT: stream=
Test results for InstrumentationTestRunner=.E
Time: 6.729
FAILURES!!!
Tests run: 1, Failures: 0, Errors: 1
INSTRUMENTATION_CODE: -1
songlixin@zjujoe-desktop:~/mydroid/out/host/linux-x86/cts/android-cts/repository/testcases$
修改
出错信息说是找不到:calendar
修改代码,使其不启动 calendar:
//launchActivity("com.android.calendar", "LaunchActivity", true);
//Thread.sleep(ACTIVITY_STARTUP_WAIT_TIME);
重新编译: make cts
重新安装
重新安装用:adb install -r CtsPerformanceTestCases.apk
运行(成功)
~/mydroid/out/host/linux-x86/cts/android-cts/repository/testcases$
adb shell am instrument -w -r com.android.cts.performance/android.test.InstrumentationTestRunner
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: current=1
INSTRUMENTATION_STATUS: class=android.performance.cts.MultiAppStartupTest
INSTRUMENTATION_STATUS: stream=
android.performance.cts.MultiAppStartupTest:
INSTRUMENTATION_STATUS: numtests=1
INSTRUMENTATION_STATUS: test=testMultipleApps
INSTRUMENTATION_STATUS_CODE: 1
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: current=1
INSTRUMENTATION_STATUS: class=android.performance.cts.MultiAppStartupTest
INSTRUMENTATION_STATUS: stream=.
INSTRUMENTATION_STATUS: numtests=1
INSTRUMENTATION_STATUS: test=testMultipleApps
INSTRUMENTATION_STATUS_CODE: 0
INSTRUMENTATION_RESULT: stream=
Test results for InstrumentationTestRunner=.
Time: 7.389
OK (1 test)
总结
至此,我们大体知道如何运行 cts, 配置 cts, 扩充 cts, 下一步就看具体实践了!
参考链接里有如何添加一个 cts 测试、修改 test plan 的信息,所以本文就没有重复。
参考
Android CTS (Compatibility Test Suite) introduction
http://androidboss.com/android-cts-compatibility-test-suite-introduction-2/