我有一个模块,可以构建一个名为MyApp的应用程序。我有另一个为该应用程序构建一些测试用例,称为MyAppTests。他们都建立自己的APK,他们都在我的IDE中工作正常。我想用ant构建它们,以便我可以利用持续集成。
构建应用模块可以正常工作。我很难让Test模块编译运行。
使用来自previous question的Christopher的提示,我使用android create test-project -p MyAppTests -m ../MyApp -n MyAppTests
创建必要的构建文件来构建和运行我的测试项目。这似乎工作得很好(一旦我删除了为我构造的不必要的测试用例并将我的AndroidManifest.xml恢复到我用android create
替换之前使用的那个),但我有两个问题。
第一个问题:项目无法编译,因为它缺少库。
$ ant run-tests
Buildfile: build.xml
[setup] Project Target: Google APIs
[setup] Vendor: Google Inc.
[setup] Platform Version: 1.6
[setup] API level: 4
[setup] WARNING: No minSdkVersion value set. Application will install on all Android versions.
-install-tested-project:
[setup] Project Target: Google APIs
[setup] Vendor: Google Inc.
[setup] Platform Version: 1.6
[setup] API level: 4
[setup] WARNING: No minSdkVersion value set. Application will install on all Android versions.
-compile-tested-if-test:
-dirs:
[echo] Creating output directories if needed...
-resource-src:
[echo] Generating R.java / Manifest.java from the resources...
-aidl:
[echo] Compiling aidl files into Java classes...
compile:
[javac] Compiling 1 source file to /Users/mike/Projects/myapp/android/MyApp/bin/classes
-dex:
[echo] Converting compiled files and external libraries into /Users/mike/Projects/myapp/android/MyApp/bin/classes.dex...
[echo]
-package-resources:
[echo] Packaging resources
[aaptexec] Creating full resource package...
-package-debug-sign:
[apkbuilder] Creating MyApp-debug-unaligned.apk and signing it with a debug key...
[apkbuilder] Using keystore: /Users/mike/.android/debug.keystore
debug:
[echo] Running zip align on final apk...
[echo] Debug Package: /Users/mike/Projects/myapp/android/MyApp/bin/MyApp-debug.apk
install:
[echo] Installing /Users/mike/Projects/myapp/android/MyApp/bin/MyApp-debug.apk onto default emulator or device...
[exec] 1567 KB/s (288354 bytes in 0.179s)
[exec] pkg: /data/local/tmp/MyApp-debug.apk
[exec] Success
-compile-tested-if-test:
-dirs:
[echo] Creating output directories if needed...
[mkdir] Created dir: /Users/mike/Projects/myapp/android/MyAppTests/gen
[mkdir] Created dir: /Users/mike/Projects/myapp/android/MyAppTests/bin
[mkdir] Created dir: /Users/mike/Projects/myapp/android/MyAppTests/bin/classes
-resource-src:
[echo] Generating R.java / Manifest.java from the resources...
-aidl:
[echo] Compiling aidl files into Java classes...
compile:
[javac] Compiling 5 source files to /Users/mike/Projects/myapp/android/MyAppTests/bin/classes
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/GsonTest.java:4: package roboguice.test does not exist
[javac] import roboguice.test.RoboUnitTestCase;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/GsonTest.java:8: package com.google.gson does not exist
[javac] import com.google.gson.JsonElement;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/GsonTest.java:9: package com.google.gson does not exist
[javac] import com.google.gson.JsonParser;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/GsonTest.java:11: cannot find symbol
[javac] symbol: class RoboUnitTestCase
[javac] public class GsonTest extends RoboUnitTestCase<MyApplication> {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:6: package roboguice.test does not exist
[javac] import roboguice.test.RoboUnitTestCase;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:7: package roboguice.util does not exist
[javac] import roboguice.util.RoboLooperThread;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:11: package com.google.gson does not exist
[javac] import com.google.gson.JsonObject;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:15: cannot find symbol
[javac] symbol: class RoboUnitTestCase
[javac] public class HttpTest extends RoboUnitTestCase<MyApplication> {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/LinksTest.java:4: package roboguice.test does not exist
[javac] import roboguice.test.RoboUnitTestCase;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/LinksTest.java:12: cannot find symbol
[javac] symbol: class RoboUnitTestCase
[javac] public class LinksTest extends RoboUnitTestCase<MyApplication> {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:4: package roboguice.test does not exist
[javac] import roboguice.test.RoboUnitTestCase;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:5: package roboguice.util does not exist
[javac] import roboguice.util.RoboAsyncTask;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:6: package roboguice.util does not exist
[javac] import roboguice.util.RoboLooperThread;
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:12: cannot find symbol
[javac] symbol: class RoboUnitTestCase
[javac] public class SafeAsyncTest extends RoboUnitTestCase<MyApplication> {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyApp/bin/classes/com/myapp/activity/Stories.class: warning: Cannot find annotation method 'value()' in type 'roboguice.inject.InjectResource': class file for roboguice.inject.InjectResource not found
[javac] /Users/mike/Projects/myapp/android/MyApp/bin/classes/com/myapp/activity/Stories.class: warning: Cannot find annotation method 'value()' in type 'roboguice.inject.InjectResource'
[javac] /Users/mike/Projects/myapp/android/MyApp/bin/classes/com/myapp/activity/Stories.class: warning: Cannot find annotation method 'value()' in type 'roboguice.inject.InjectView': class file for roboguice.inject.InjectView not found
[javac] /Users/mike/Projects/myapp/android/MyApp/bin/classes/com/myapp/activity/Stories.class: warning: Cannot find annotation method 'value()' in type 'roboguice.inject.InjectView'
[javac] /Users/mike/Projects/myapp/android/MyApp/bin/classes/com/myapp/activity/Stories.class: warning: Cannot find annotation method 'value()' in type 'roboguice.inject.InjectView'
[javac] /Users/mike/Projects/myapp/android/MyApp/bin/classes/com/myapp/activity/Stories.class: warning: Cannot find annotation method 'value()' in type 'roboguice.inject.InjectView'
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/GsonTest.java:15: cannot find symbol
[javac] symbol : class JsonParser
[javac] location: class com.myapp.test.GsonTest
[javac] final JsonParser parser = new JsonParser();
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/GsonTest.java:15: cannot find symbol
[javac] symbol : class JsonParser
[javac] location: class com.myapp.test.GsonTest
[javac] final JsonParser parser = new JsonParser();
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/GsonTest.java:18: cannot find symbol
[javac] symbol : class JsonElement
[javac] location: class com.myapp.test.GsonTest
[javac] final JsonElement e = parser.parse(s);
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/GsonTest.java:20: cannot find symbol
[javac] symbol : class JsonElement
[javac] location: class com.myapp.test.GsonTest
[javac] final JsonElement e2 = parser.parse(s2);
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:19: cannot find symbol
[javac] symbol : method getInstrumentation()
[javac] location: class com.myapp.test.HttpTest
[javac] assertEquals("MyApp", getInstrumentation().getTargetContext().getResources().getString(com.myapp.R.string.app_name));
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:62: cannot find symbol
[javac] symbol : class RoboLooperThread
[javac] location: class com.myapp.test.HttpTest
[javac] new RoboLooperThread() {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:82: cannot find symbol
[javac] symbol : method assertTrue(java.lang.String,boolean)
[javac] location: class com.myapp.test.HttpTest
[javac] assertTrue(result[0], result[0].contains("Search"));
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:87: cannot find symbol
[javac] symbol : class JsonObject
[javac] location: class com.myapp.test.HttpTest
[javac] final JsonObject[] result = {null};
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:90: cannot find symbol
[javac] symbol : class RoboLooperThread
[javac] location: class com.myapp.test.HttpTest
[javac] new RoboLooperThread() {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:117: cannot find symbol
[javac] symbol : class JsonObject
[javac] location: class com.myapp.test.HttpTest
[javac] final JsonObject[] result = {null};
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/HttpTest.java:120: cannot find symbol
[javac] symbol : class RoboLooperThread
[javac] location: class com.myapp.test.HttpTest
[javac] new RoboLooperThread() {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/LinksTest.java:27: cannot find symbol
[javac] symbol : method assertTrue(boolean)
[javac] location: class com.myapp.test.LinksTest
[javac] assertTrue(m.matches());
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/LinksTest.java:28: cannot find symbol
[javac] symbol : method assertEquals(java.lang.String,java.lang.String)
[javac] location: class com.myapp.test.LinksTest
[javac] assertEquals( map.get(url), m.group(1) );
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:19: cannot find symbol
[javac] symbol : method getInstrumentation()
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] assertEquals("MyApp", getInstrumentation().getTargetContext().getString(com.myapp.R.string.app_name));
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:27: cannot find symbol
[javac] symbol : class RoboLooperThread
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] new RoboLooperThread() {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:65: cannot find symbol
[javac] symbol : method assertEquals(com.myapp.test.SafeAsyncTest.State,com.myapp.test.SafeAsyncTest.State)
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] assertEquals(State.TEST_SUCCESS,state[0]);
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:74: cannot find symbol
[javac] symbol : class RoboLooperThread
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] new RoboLooperThread() {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:105: cannot find symbol
[javac] symbol : method assertEquals(com.myapp.test.SafeAsyncTest.State,com.myapp.test.SafeAsyncTest.State)
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] assertEquals(State.TEST_SUCCESS,state[0]);
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:113: cannot find symbol
[javac] symbol : class RoboLooperThread
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] new RoboLooperThread() {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:144: cannot find symbol
[javac] symbol : method assertEquals(com.myapp.test.SafeAsyncTest.State,com.myapp.test.SafeAsyncTest.State)
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] assertEquals(State.TEST_SUCCESS,state[0]);
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:154: cannot find symbol
[javac] symbol : class RoboLooperThread
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] new RoboLooperThread() {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java:187: cannot find symbol
[javac] symbol : method assertEquals(com.myapp.test.SafeAsyncTest.State,com.myapp.test.SafeAsyncTest.State)
[javac] location: class com.myapp.test.SafeAsyncTest
[javac] assertEquals(State.TEST_SUCCESS,state[0]);
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/StoriesTest.java:11: cannot access roboguice.activity.GuiceListActivity
[javac] class file for roboguice.activity.GuiceListActivity not found
[javac] public class StoriesTest extends ActivityUnitTestCase<Stories> {
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/StoriesTest.java:21: cannot access roboguice.application.GuiceApplication
[javac] class file for roboguice.application.GuiceApplication not found
[javac] setApplication( new MyApplication( getInstrumentation().getTargetContext() ) );
[javac] ^
[javac] /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/StoriesTest.java:22: incompatible types
[javac] found : com.myapp.activity.Stories
[javac] required: android.app.Activity
[javac] final Activity activity = startActivity(intent, null, null);
[javac] ^
[javac] 39 errors
[javac] 6 warnings
BUILD FAILED
/opt/local/android-sdk-mac/platforms/android-1.6/templates/android_rules.xml:248: Compile failed; see the compiler error output for details.
Total time: 24 seconds
这不是一个难以解决的问题。我不确定这是正确的做法,但我将缺少的库(roboguice和gson)从MyApp / libs目录复制到MyAppTests / libs目录,一切似乎都可以正常编译。
但这导致了第二个问题,我目前仍然坚持这个问题。测试编译正常,但它们不会运行:
$ cp ../MyApp/libs/gson-r538.jar libs/
$ cp ../MyApp/libs/roboguice-1.1-SNAPSHOT.jar libs/
0 10:23 /Users/mike/Projects/myapp/android/MyAppTests $ ant run-testsBuildfile: build.xml
[setup] Project Target: Google APIs
[setup] Vendor: Google Inc.
[setup] Platform Version: 1.6
[setup] API level: 4
[setup] WARNING: No minSdkVersion value set. Application will install on all Android versions.
-install-tested-project:
[setup] Project Target: Google APIs
[setup] Vendor: Google Inc.
[setup] Platform Version: 1.6
[setup] API level: 4
[setup] WARNING: No minSdkVersion value set. Application will install on all Android versions.
-compile-tested-if-test:
-dirs:
[echo] Creating output directories if needed...
-resource-src:
[echo] Generating R.java / Manifest.java from the resources...
-aidl:
[echo] Compiling aidl files into Java classes...
compile:
[javac] Compiling 1 source file to /Users/mike/Projects/myapp/android/MyApp/bin/classes
-dex:
[echo] Converting compiled files and external libraries into /Users/mike/Projects/myapp/android/MyApp/bin/classes.dex...
[echo]
-package-resources:
[echo] Packaging resources
[aaptexec] Creating full resource package...
-package-debug-sign:
[apkbuilder] Creating MyApp-debug-unaligned.apk and signing it with a debug key...
[apkbuilder] Using keystore: /Users/mike/.android/debug.keystore
debug:
[echo] Running zip align on final apk...
[echo] Debug Package: /Users/mike/Projects/myapp/android/MyApp/bin/MyApp-debug.apk
install:
[echo] Installing /Users/mike/Projects/myapp/android/MyApp/bin/MyApp-debug.apk onto default emulator or device...
[exec] 1396 KB/s (288354 bytes in 0.201s)
[exec] pkg: /data/local/tmp/MyApp-debug.apk
[exec] Success
-compile-tested-if-test:
-dirs:
[echo] Creating output directories if needed...
-resource-src:
[echo] Generating R.java / Manifest.java from the resources...
-aidl:
[echo] Compiling aidl files into Java classes...
compile:
[javac] Compiling 5 source files to /Users/mike/Projects/myapp/android/MyAppTests/bin/classes
[javac] Note: /Users/mike/Projects/myapp/android/MyAppTests/src/com/myapp/test/SafeAsyncTest.java uses unchecked or unsafe operations.
[javac] Note: Recompile with -Xlint:unchecked for details.
-dex:
[echo] Converting compiled files and external libraries into /Users/mike/Projects/myapp/android/MyAppTests/bin/classes.dex...
[echo]
-package-resources:
[echo] Packaging resources
[aaptexec] Creating full resource package...
-package-debug-sign:
[apkbuilder] Creating MyAppTests-debug-unaligned.apk and signing it with a debug key...
[apkbuilder] Using keystore: /Users/mike/.android/debug.keystore
debug:
[echo] Running zip align on final apk...
[echo] Debug Package: /Users/mike/Projects/myapp/android/MyAppTests/bin/MyAppTests-debug.apk
install:
[echo] Installing /Users/mike/Projects/myapp/android/MyAppTests/bin/MyAppTests-debug.apk onto default emulator or device...
[exec] 1227 KB/s (94595 bytes in 0.075s)
[exec] pkg: /data/local/tmp/MyAppTests-debug.apk
[exec] Success
run-tests:
[echo] Running tests ...
[exec]
[exec] android.test.suitebuilder.TestSuiteBuilder$FailedToCreateTests:INSTRUMENTATION_RESULT: shortMsg=Class ref in pre-verified class resolved to unexpected implementation
[exec] INSTRUMENTATION_RESULT: longMsg=java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
[exec] INSTRUMENTATION_CODE: 0
BUILD SUCCESSFUL
Total time: 38 seconds
知道是什么导致“预验证类中的类引用解决了意外实现”错误?
答案 0 :(得分:19)
如果使用Eclipse,更简单的方法是不在测试项目中包含外部库,而是将其导出到Eclipse Project设置中。这将解决问题
前一段时间,我写了一篇博文,解释了这一点: http://juristr.com/blog/2010/06/android-instrumentation-test/
答案 1 :(得分:13)
问题是android ant构建脚本中存在一个错误,在编译测试项目时不包含测试项目的libs目录。如果你试图通过将libs复制到测试人员项目的libs目录来解决这个问题,你会像我一样在运行时遇到类验证问题,正如fadden所指出的那样。
解决方案是调整原来在android compile
中的android_test_rules.xml
目标,将<fileset dir="${tested.project.absolute.dir}/libs" includes="*.jar" />
添加到<classpath>
指令。
以下是修订后的compile
目标。通过将它添加到TESTER项目的build.xml中,它将优先于android_test_rules.xml中的那个:
<!-- override "compile" target in platform android_rules.xml to include tested app's external libraries -->
<target name="compile" depends="-resource-src, -aidl"
description="Compiles project's .java files into .class files">
<!-- If android rules are used for a test project, its classpath should include
tested project's location -->
<condition property="extensible.classpath"
value="${tested.project.absolute.dir}/bin/classes" else=".">
<isset property="tested.project.absolute.dir" />
</condition>
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
destdir="${out.classes.absolute.dir}"
bootclasspathref="android.target.classpath"
verbose="${verbose}" classpath="${extensible.classpath}">
<src path="${source.absolute.dir}" />
<src path="${gen.absolute.dir}" />
<classpath>
<fileset dir="${tested.project.absolute.dir}/libs" includes="*.jar" />
<fileset dir="${external.libs.absolute.dir}" includes="*.jar" />
</classpath>
</javac>
</target>
答案 2 :(得分:8)
我有一个类似的问题,使用Intellij IDEA(11.1.1)。我的应用程序可以很好地构建和部署到设备上,当我尝试运行它时,我的测试应用程序会发出大量的dex错误:“预验证类中的类ref解决了意外实现”......
app test-app common-libs app depends on common-libs (and exports common-libs) test-app depends on app
这篇文章帮助我弄清楚问题是应用程序和测试应用程序.dex文件中的重复类文件,然后我手动验证。事实证明,为了从test-app中排除app类,在test-app的模块设置中,我需要将它的依赖项app的范围从“compile”改为“提供”。
答案 3 :(得分:6)
我在上面的文字中没有看到实际的错误信息,但我想我可以回答。
通常,警告的发生是因为相同的代码出现在两个不同的APK中。一个APK中的实现用于预验证和优化,但另一个实现在执行期间使用。 VM检测到这种情况并拒绝该类,因为验证和优化是通过一组不再适用的假设来执行的。
解决此问题的方法是确保VM只有一个类可用。这可能需要更多地与构建脚本作斗争。
您可以使用“dexdump”查看APK的内容。 (还有“dexlist”,这有点简洁,但我不记得那是否是SDK的一部分。)
答案 4 :(得分:2)
就像@fadden所说,相同的代码在两个不同的APK中。这可以是例如当您的测试和测试项目都依赖于相同的android库项目时发生。这不一定是直接的,因为图书馆项目可以依赖于其他图书馆项目。
ant规则文件中的问题似乎已修复。至少在SDK工具r11中。编译目标可以在mail_rules.xml
而不是test_rules.xml
中找到,仅适用于那些感到困惑的人。
答案 5 :(得分:0)
您是否尝试在测试apk中包含.class文件,而不是从原始项目生成新的.class文件?这解决了我的问题。
答案 6 :(得分:0)
我遇到了与maven运行的单元测试相同的问题。 通过删除已经由主项目导入的android库的链接,问题得到了解决。
答案 7 :(得分:0)
要测试的项目范围应该是编译的,并且应该提供库的范围。
如需了解更多信息,请阅读here
答案 8 :(得分:0)
android update test-project -m <project path> -p <test project path>
ant clean
ant debug
运行这些命令后,您可以运行ant测试。注意:如果它给出了与JUnit相关的错误,请在测试项目libs文件夹中添加Junit jar文件。