使用 ant 和库项目进行 Android 单元测试

发布于 2024-12-22 03:40:43 字数 2987 浏览 2 评论 0原文

似乎最新的 android SDK 工具仍然不能正确支持包含链接库项目的应用程序的测试。

我有一个具有以下设置的项目:

TestLib (android 库项目) <- TestMain (android 项目) <- TestMainTest (android 单元测试项目)

我在 eclipse 中创建了所有这些项目,然后使用 android update (test -/lib-)project ... 生成 build.xml 等。等人。

一旦 TestMain 中的类(在我的示例中为 InheritAddition.java)继承自 TestLib 中的类 (Addition.java),并且您想要在单元测试 (InheritAdditionTest.java) 中引用此类。

TestLib

public class Addition {
    public int add2(int o1, int o2) {
      return o1 + o2;
    }
}

TestMain

public class InheritAddition extends Addition {
    public int sub(int p1, int p2) {
        return p1 - p2;
    }
}

TestMainTest

public class InheritAdditionTest extends AndroidTestCase {
    public void testSub() {
        Assert.assertEquals(2, new InheritAddition().sub(3, 1));
    }
}

在命令行上构建时,结果如下:

W/ClassPathPackageInfoSource(14871): Caused by: java.lang.NoClassDefFoundError: org/test/main/InheritAddition
W/ClassPathPackageInfoSource(14871):    ... 26 more
W/ClassPathPackageInfoSource(14871): Caused by: java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
W/ClassPathPackageInfoSource(14871):    at dalvik.system.DexFile.defineClass(Native Method)
W/ClassPathPackageInfoSource(14871):    at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:195)
W/ClassPathPackageInfoSource(14871):    at dalvik.system.DexPathList.findClass(DexPathList.java:315)
W/ClassPathPackageInfoSource(14871):    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:58)
W/ClassPathPackageInfoSource(14871):    at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
W/ClassPathPackageInfoSource(14871):    at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
W/ClassPathPackageInfoSource(14871):    ... 26 more
W/dalvikvm(14871): Class resolved by unexpected DEX: Lorg/test/main/InheritAddition;(0x41356250):0x13772e0 ref [Lorg/test/lib/Addition;] Lorg/test/lib/Addition;(0x41356250):0x13ba910

我发现了一些适用于 eclipse 的解决方法:

当测试项目在库中有 jar 时,无法构建和运行使用“ant create test-project”创建的 Android 测试项目目录

这确实有效,但我正在寻找一个与 ANT 一起使用的解决方案(更准确地说,我正在寻找一个同时适用于两者的解决方案)。

记录的方法(通过更改 build.xml 以将主项目中的 jar 包含到类路径中)在这里不适用,因为示例项目不使用任何库 jar(我也相信这个特定问题现在已通过 SDK 工具修复) r16)。

我想解决这个问题的强力方法是尝试以某种方式删除 TestMainTestTestLib 的依赖关系(通过修改 project.properties)并且相反,设法破解构建脚本,将这些构建的 jar 放入类路径中(因此将 -compile 目标替换为修改 javac 类路径的内容)。由于我长期以来一直试图跟上 android SDK 工具链的变化,这并不是我最喜欢的选项,因为它 a) 相当复杂,b) 需要不断修改 build.xml工具链发生变化(这种情况相当频繁)。

所以我正在寻找如何在不使用大锤的情况下让这样的设置工作的想法。也许我错过了一些完全明显的东西,但对我来说,这个用例是相当标准的,我很难理解为什么不支持开箱即用。

It seems that also the latest android SDK tools still don't properly support testing of applications that contain linked library projects.

I have a project with the following setup:

TestLib (android library project) <- TestMain (android project) <- TestMainTest (android unit test project)

I created all those projects in eclipse and then used android update (test-/lib-)project ... to generate the build.xml et. al.

The problem starts as soon as you have a class in TestMain (InheritAddition.java in my example) that inherits from a class in TestLib (Addition.java) and you want to reference this class in the unit test (InheritAdditionTest.java).

TestLib

public class Addition {
    public int add2(int o1, int o2) {
      return o1 + o2;
    }
}

TestMain

public class InheritAddition extends Addition {
    public int sub(int p1, int p2) {
        return p1 - p2;
    }
}

TestMainTest

public class InheritAdditionTest extends AndroidTestCase {
    public void testSub() {
        Assert.assertEquals(2, new InheritAddition().sub(3, 1));
    }
}

When building on the command line the result is the following:

W/ClassPathPackageInfoSource(14871): Caused by: java.lang.NoClassDefFoundError: org/test/main/InheritAddition
W/ClassPathPackageInfoSource(14871):    ... 26 more
W/ClassPathPackageInfoSource(14871): Caused by: java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
W/ClassPathPackageInfoSource(14871):    at dalvik.system.DexFile.defineClass(Native Method)
W/ClassPathPackageInfoSource(14871):    at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:195)
W/ClassPathPackageInfoSource(14871):    at dalvik.system.DexPathList.findClass(DexPathList.java:315)
W/ClassPathPackageInfoSource(14871):    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:58)
W/ClassPathPackageInfoSource(14871):    at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
W/ClassPathPackageInfoSource(14871):    at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
W/ClassPathPackageInfoSource(14871):    ... 26 more
W/dalvikvm(14871): Class resolved by unexpected DEX: Lorg/test/main/InheritAddition;(0x41356250):0x13772e0 ref [Lorg/test/lib/Addition;] Lorg/test/lib/Addition;(0x41356250):0x13ba910

I found some workaround that works for eclipse:

Can't build and run an android test project created using "ant create test-project" when tested project has jars in libs directory

That does the trick, but I am looking for a solution that works with ANT (more precisely I am looking for a solution that works on both at the same time).

The documented approach (by changing build.xml to include jars from the main project into the class path) is not applicable here as the sample project doesn't use any library jars (also I believe that this particular problem is now fixed with SDK tools r16).

I guess the brute force way of solving that is to try and somehow remove the dependencies of TestMainTest to TestLib (by modifying project.properties) and instead manage to hack the build script to put those built jars into the class path (so replace the -compile target with something that modifies the class path for javac). Since I have a long history of trying to keep up with android SDK toolchain changes, this is not really my favorite option as it is a) rather complicated and b) requires constant modification of the build.xml whenever the toolchain changes (which is quite frequently).

So I am looking for ideas of how to get such a setup working without using the sledge hammer. Maybe I am missing something totally obvious but for me this use case is fairly standard and I have a hard time understanding why this isn't supported out of the box.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

暗恋未遂 2024-12-29 03:40:43

使用 Android SDK 工具 r15 和 Eclipse。

假设在eclipse中创建三个项目:Lib(android库项目)<-App(android应用程序项目)<-Test(android单元测试项目)并定义以下类:

[Lib]

public class A {}

[App]

public class A extends B {}

[Test]

public class MyUnitTest extends AndroidTestCase {
    public void test() {
        new A();
        new B();
    }
}

在此setup TestMain 将 TestLib 引用为 Android 库,并且 TestMainTest 有一个对 TestMain 的项目引用。

您应该看到 Test 无法编译,因为 A 无法解析。这是预期的,因为测试无法看到 Lib。一种解决方案是将库引用从 Test 添加到 Lib。虽然这解决了编译问题,但它在运行时会中断。结果是一堆错误,但有趣的是:

W/dalvikvm( 9275): Class resolved by unexpected DEX: Lcom/example/B;(0x40513450):0x294c70 ref [Lcom/example/A;] Lcom/example/A;(0x40513450):0x8f600
W/dalvikvm( 9275): (Lcom/example/B; had used a different Lcom/example/A; during pre-verification)
W/dalvikvm( 9275): Unable to resolve superclass of Lcom/example/B; (1)
W/dalvikvm( 9275): Link of class 'Lcom/example/B;' failed
E/dalvikvm( 9275): Could not find class 'com.example.B', referenced from method com.example.test.MyUnitTest.test
W/dalvikvm( 9275): VFY: unable to resolve new-instance 3 (Lcom/example/B;) in Lcom/example/test/MyUnitTest;
D/dalvikvm( 9275): VFY: replacing opcode 0x22 at 0x0000
D/dalvikvm( 9275): VFY: dead code 0x0002-000a in Lcom/example/test/MyUnitTest;.test ()V

这是因为 Test 和 App 项目都引用了 Lib 库项目,因此两个生成的 apk 都包含 com.example.A 的副本。

不要在 Eclipse 中添加从测试项目到库项目的显式依赖项(如果该库是被测应用程序项目的依赖项)。这样做可能会导致应用程序和测试项目在生成的 apk 中包含相同类的副本,并且测试将在运行时失败。

我们需要找到解决编译时可见性问题的方法。在运行时,测试将可以看到 App 以及 Lib 中的类。不要创建从 Test 到 Lib 的库引用,而是更新 App 的构建路径以导出其库项目。现在测试已编译并且单元测试成功运行。

在 Eclipse 中,要测试引用库项目的应用程序项目,请从其构建路径设置中的应用程序项目导出库项目。

现在 Eclipse 中一切正常,但是 Ant 呢?使用 android update [lib-|test-]project 命令创建必要的 build.xml 文件。确保在所有三个目录中运行 Ant clean:Lib、App 和 Test。未能清理所有三个项目可能会导致编译成功。

Ant 编译将失败并显示:

[javac] ...Test/src/com/example/test/MyUnitTest.java:3: cannot find symbol
[javac] symbol  : class A
[javac] location: package com.example
[javac] import com.example.A;
[javac]                   ^
[javac] ...Test/src/com/example/test/MyUnitTest.java:10: cannot access com.example.A
[javac] class file for com.example.A not found
[javac]         new B();
[javac]         ^
[javac] ...Test/src/com/example/test/MyUnitTest.java:11: cannot find symbol
[javac] symbol  : class A
[javac] location: class com.example.test.MyUnitTest
[javac]         new A();
[javac]             ^
[javac] 3 errors

为什么 Eclipse 构建成功时 Ant 构建失败? Eclipse 和 Ant 构建系统是不同的。从 Eclipse 中的 App 导出库项目不会影响 Ant 构建。构建失败,因为测试项目无法看到 Lib 项目。如果我们尝试通过将 android.library.reference 属性添加到 Test/project.properties 来解决此问题,那么我们所做的事情与在 Eclipse 中将库引用从 Test 添加到 Lib 完全相同。 Ant 构建会成功,但测试会在运行时失败,并出现熟悉的“类由意外的 DEX 解析”错误。

我们需要一种方法让测试项目针对库项目进行编译,但不将其包含在 deshing 过程中。此过程有两个步骤。首先,包含从 Test 到 Lib 的引用,该引用不会影响 Eclipse。其次,更新 Ant 构建系统,以便对库进行编译,但将其排除在 deshing 之外。

在 Test/build.xml 的顶部,我定义了一个指向该库的属性。这类似于添加对 Test/project.properties 的引用,只不过 Eclipse 不会看到它:

现在我们需要从 deshing 过程中排除库 jar。这需要更新 dex-helper 宏。我将宏覆盖放在 Test/build.xml 文件中的行之后。新的 dex-helper 从 dexing 过程中排除所有不在 Test 项目文件夹树中的 jar 文件:

<macrodef name="dex-helper">
  <element name="external-libs" optional="yes"/>
  <attribute name="nolocals" default="false"/>
  <sequential>
    <!-- sets the primary input for dex. If a pre-dex task sets it to
                 something else this has no effect -->
    <property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}"/>
    <!-- set the secondary dx input: the project (and library) jar files
                 If a pre-dex task sets it to something else this has no effect -->
    <if>
      <condition>
        <isreference refid="out.dex.jar.input.ref"/>
      </condition>
      <else>
        <!--
                        out.dex.jar.input.ref is not set. Compile the list of jars to dex.
                        For test projects, only dex jar files included in the project
                        path
                    -->
        <if condition="${project.is.test}">
          <then>
            <!-- test project -->
            <pathconvert pathsep="," refid="jar.libs.ref" property="jars_to_dex_pattern"/>
            <path id="out.dex.jar.input.ref">
              <files includes="${jars_to_dex_pattern}">
                <!-- only include jar files actually in the test project -->
                <filename name="${basedir}/**/*"/>
              </files>
            </path>
            <property name="in_jars_to_dex" refid="jar.libs.ref"/>
            <property name="out_jars_to_dex" refid="out.dex.jar.input.ref"/>
            <echo message="Test project! Reducing jars to dex from ${in_jars_to_dex} to ${out_jars_to_dex}."/>
          </then>
          <else>
            <path id="out.dex.jar.input.ref"/>
          </else>
        </if>
      </else>
    </if>
    <dex executable="${dx}" output="${intermediate.dex.file}" nolocals="@{nolocals}" verbose="${verbose}">
      <path path="${out.dex.input.absolute.dir}"/>
      <path refid="out.dex.jar.input.ref"/>
      <external-libs/>
    </dex>
  </sequential>
</macrodef>

完成这些更改后,Test 将在 Eclipse 和 Ant 中构建和运行。

测试愉快!

其他注意事项:
如果 Eclipse 中没有构建,而您认为应该构建,请尝试按以下顺序刷新项目:Lib、App、Test。我经常需要在更改构建路径后执行此操作。有时我还必须进行干净的构建才能正常工作。

Using Android SDK Tools r15 and Eclipse.

Suppose you create three projects in eclipse: Lib (android library project) <- App (android application project) <- Test (android unit test project) and define the following classes:

[Lib]

public class A {}

[App]

public class A extends B {}

[Test]

public class MyUnitTest extends AndroidTestCase {
    public void test() {
        new A();
        new B();
    }
}

In this setup TestMain references TestLib as an Android library and TestMainTest has a project reference to TestMain.

You should see that Test doesn’t compile because A cannot be resolved. This is expected because Test has no visibility into Lib. One solution is to add a library reference from Test to Lib. While this fixes the compile problem, it breaks at run time. A bunch of errors result, but this is the interesting one:

W/dalvikvm( 9275): Class resolved by unexpected DEX: Lcom/example/B;(0x40513450):0x294c70 ref [Lcom/example/A;] Lcom/example/A;(0x40513450):0x8f600
W/dalvikvm( 9275): (Lcom/example/B; had used a different Lcom/example/A; during pre-verification)
W/dalvikvm( 9275): Unable to resolve superclass of Lcom/example/B; (1)
W/dalvikvm( 9275): Link of class 'Lcom/example/B;' failed
E/dalvikvm( 9275): Could not find class 'com.example.B', referenced from method com.example.test.MyUnitTest.test
W/dalvikvm( 9275): VFY: unable to resolve new-instance 3 (Lcom/example/B;) in Lcom/example/test/MyUnitTest;
D/dalvikvm( 9275): VFY: replacing opcode 0x22 at 0x0000
D/dalvikvm( 9275): VFY: dead code 0x0002-000a in Lcom/example/test/MyUnitTest;.test ()V

This is because both the Test and App projects reference the Lib library project, so both resulting apks include a copy of com.example.A.

Do not add explicit dependencies in eclipse from a test project to a library project (if that library is a dependency of the application project under test). Doing so can cause both the application and test projects to include copies of the same classes in their resulting apks and the test will fail at run time.

We need to find a way around the compile time visibility issue. At run time, Test will have visibility into App and therefore the classes in Lib. Instead of creating a library reference from Test to Lib, update the build path of App to export it’s library projects. Now Test compiles and the unit test successfully runs.

In Eclipse, to test an application project that references a library project, export the library projects from the application project in it’s build path settings.

Everything works in Eclipse now, but that about Ant? Use the android update [lib-|test-]project commands to create the necessary build.xml files. Be sure to run Ant clean in all three directories: Lib, App, and Test. Failure to clean all three projects may result in a successful compile.

The Ant compile will fail with:

[javac] ...Test/src/com/example/test/MyUnitTest.java:3: cannot find symbol
[javac] symbol  : class A
[javac] location: package com.example
[javac] import com.example.A;
[javac]                   ^
[javac] ...Test/src/com/example/test/MyUnitTest.java:10: cannot access com.example.A
[javac] class file for com.example.A not found
[javac]         new B();
[javac]         ^
[javac] ...Test/src/com/example/test/MyUnitTest.java:11: cannot find symbol
[javac] symbol  : class A
[javac] location: class com.example.test.MyUnitTest
[javac]         new A();
[javac]             ^
[javac] 3 errors

Why does the Ant build fail when the Eclipse build succeeds? The Eclipse and Ant build systems are distinct. Exporting the library projects from App in Eclipse has not effect on the Ant build. The build failed because the Test project doesn’t have visibility into the Lib project. If we try to solve this problem by adding an android.library.refernce property to Test/project.properties, we have done exactly the same thing as adding a library reference from Test to Lib in Eclipse. The Ant build would succeed, but the test would fail at run time with the familiar “Class resolved by unexpected DEX” error.

We need a way for the test project to compile against the library project, but not include it in the dexing process. There are two steps to this process. First, include a reference from Test to Lib that does not affect Eclipse. Second, update the Ant build system so the library is compiled against but in excluded from dexing.

At the top of Test/build.xml I define a property that points to the library. This is similar to adding a reference to Test/project.properties except that Eclipse won’t see it:

Now we need to exclude the library jar from the dexing process. This requires updating the dex-helper macro. I place the macro override after the line in my Test/build.xml file. The new dex-helper excludes all jar files not in the Test project folder tree from the dexing process:

<macrodef name="dex-helper">
  <element name="external-libs" optional="yes"/>
  <attribute name="nolocals" default="false"/>
  <sequential>
    <!-- sets the primary input for dex. If a pre-dex task sets it to
                 something else this has no effect -->
    <property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}"/>
    <!-- set the secondary dx input: the project (and library) jar files
                 If a pre-dex task sets it to something else this has no effect -->
    <if>
      <condition>
        <isreference refid="out.dex.jar.input.ref"/>
      </condition>
      <else>
        <!--
                        out.dex.jar.input.ref is not set. Compile the list of jars to dex.
                        For test projects, only dex jar files included in the project
                        path
                    -->
        <if condition="${project.is.test}">
          <then>
            <!-- test project -->
            <pathconvert pathsep="," refid="jar.libs.ref" property="jars_to_dex_pattern"/>
            <path id="out.dex.jar.input.ref">
              <files includes="${jars_to_dex_pattern}">
                <!-- only include jar files actually in the test project -->
                <filename name="${basedir}/**/*"/>
              </files>
            </path>
            <property name="in_jars_to_dex" refid="jar.libs.ref"/>
            <property name="out_jars_to_dex" refid="out.dex.jar.input.ref"/>
            <echo message="Test project! Reducing jars to dex from ${in_jars_to_dex} to ${out_jars_to_dex}."/>
          </then>
          <else>
            <path id="out.dex.jar.input.ref"/>
          </else>
        </if>
      </else>
    </if>
    <dex executable="${dx}" output="${intermediate.dex.file}" nolocals="@{nolocals}" verbose="${verbose}">
      <path path="${out.dex.input.absolute.dir}"/>
      <path refid="out.dex.jar.input.ref"/>
      <external-libs/>
    </dex>
  </sequential>
</macrodef>

With these changes in place, Test builds and runs from both Eclipse and Ant.

Happy testing!

Other notes:
If things are not building in Eclipse and you believe they should, try refreshing the the projects in the following order: Lib, App, Test. I frequently have to do this after making build path changes. I also sometimes have to build clean for things to work properly.

请爱~陌生人 2024-12-29 03:40:43

@wallacen60 的回答很好。昨天我也得出了同样的结论。尽管如此,还有另一种选择:如果我们能找到一种方法将 lib 的 jar 包含在编译(javac,ant 文件的编译阶段)中,而不是从测试项目的 deshing 中排除 lib 的 jar,那就太好了测试,且仅在编译阶段进行,不在dexing阶段进行。

@wallacen60的解决方案还引入了3个项目的编译及其依赖项之间的巨大语义差异:在Eclipse中App依赖于lib,test依赖于App。这才是正确的做法。但在 ant 中,App 和 Test 都依赖于 Lib,对我来说似乎是一个糟糕的冗余循环。

所以,现在,我们所做的是修补测试项目的project.properties文件,使其包含这一行:

tested.android.library.reference.1=../SDK_android

并且我们修改了测试项目的ant文件,以便编译目标包含该库:(查看更改后的行,搜索单词“更改”)。

    <!-- override "compile" target in platform android_rules.xml to include tested app's external libraries -->
<!-- Compiles this project's .java files into .class files. -->
<target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile">
    <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
        <!-- 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>
        <condition property="extensible.libs.classpath"
                value="${tested.project.absolute.dir}/${jar.libs.dir}"
                else="${jar.libs.dir}">
            <isset property="tested.project.absolute.dir" />
        </condition>
        <echo message="jar libs dir : ${tested.project.target.project.libraries.jars}"/>
        <javac encoding="${java.encoding}"
                source="${java.source}" target="${java.target}"
                debug="true" extdirs="" includeantruntime="false"
                destdir="${out.classes.absolute.dir}"
                bootclasspathref="android.target.classpath"
                verbose="${verbose}"
                classpath="${extensible.classpath}"
                classpathref="jar.libs.ref">
            <src path="${source.absolute.dir}" />
            <src path="${gen.absolute.dir}" />
            <classpath>
                <!-- steff: we changed one line here !-->
                <fileset dir="${tested.android.library.reference.1}/bin/" includes="*.jar"/>
                <fileset dir="${extensible.libs.classpath}" includes="*.jar" />
            </classpath>
            <compilerarg line="${java.compilerargs}" />
        </javac>
               <!-- if the project is instrumented, intrument the classes -->
                        <if condition="${build.is.instrumented}">
                            <then>
                                <echo>Instrumenting classes from ${out.absolute.dir}/classes...</echo>
                                <!-- It only instruments class files, not any external libs -->
                                <emma enabled="true">
                                    <instr verbosity="${verbosity}"
                                           mode="overwrite"
                                           instrpath="${out.absolute.dir}/classes"
                                           outdir="${out.absolute.dir}/classes">
                                    </instr>
                                    <!-- TODO: exclusion filters on R*.class and allowing custom exclusion from
                                         user defined file -->
                                </emma>
                            </then>
                        </if>           
    </do-only-if-manifest-hasCode>
</target>

事实上,这种机制似乎是正确的,因为它模仿了 eclipse 的作用。但是eclipse在编译test的时候是能够知道App依赖lib的。唯一的区别是我们通过行(在project.properties中)在ant中手动公开了这种关系

tested.android.library.reference.1=../SDK_android

,但也可以自动执行此操作。我找不到 google ant 工具用于从 project.properties 中的 android.library.* 语句生成 librairy 项目路径 refid 的机制。但如果我能找到这种机制,我就可以在测试项目中传播这种依赖关系,就像 Eclipse 所做的那样。

所以我认为最好的办法是让谷歌知道他们有一个补丁要做,并暂时保留手动导出应用程序项目对 lib 项目的依赖关系的解决方案,以便编译测试项目。

有人可以就这个错误联系谷歌吗?

The answer of @wallacen60 is nice. I came to the same conclusion yesterday. Neverthe less, there is another option : instead of excluding the lib's jar from dexing of the test projet, it would be nice if we could find a way to include the lib's jar in the compilation (javac, compile stage of the ant file) of test, and only in the compilation stage and not the dexing stage.

The solution of @wallacen60 moreover introduces a big semantic difference between the compilation of the 3 project and their dependencies : in Eclipse App depends on lib, test depends on App. And that is the right way to do it. But in ant, both App and Test depend on Lib and seems like a bad redunduncy cycle to me.

So, for now, what we did was to patch the test project's project.properties file so that it includes this line :

tested.android.library.reference.1=../SDK_android

And we modified the ant file of the tested project so that the compile target includes the library : (look at the changed line, search for the word "change").

    <!-- override "compile" target in platform android_rules.xml to include tested app's external libraries -->
<!-- Compiles this project's .java files into .class files. -->
<target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile">
    <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
        <!-- 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>
        <condition property="extensible.libs.classpath"
                value="${tested.project.absolute.dir}/${jar.libs.dir}"
                else="${jar.libs.dir}">
            <isset property="tested.project.absolute.dir" />
        </condition>
        <echo message="jar libs dir : ${tested.project.target.project.libraries.jars}"/>
        <javac encoding="${java.encoding}"
                source="${java.source}" target="${java.target}"
                debug="true" extdirs="" includeantruntime="false"
                destdir="${out.classes.absolute.dir}"
                bootclasspathref="android.target.classpath"
                verbose="${verbose}"
                classpath="${extensible.classpath}"
                classpathref="jar.libs.ref">
            <src path="${source.absolute.dir}" />
            <src path="${gen.absolute.dir}" />
            <classpath>
                <!-- steff: we changed one line here !-->
                <fileset dir="${tested.android.library.reference.1}/bin/" includes="*.jar"/>
                <fileset dir="${extensible.libs.classpath}" includes="*.jar" />
            </classpath>
            <compilerarg line="${java.compilerargs}" />
        </javac>
               <!-- if the project is instrumented, intrument the classes -->
                        <if condition="${build.is.instrumented}">
                            <then>
                                <echo>Instrumenting classes from ${out.absolute.dir}/classes...</echo>
                                <!-- It only instruments class files, not any external libs -->
                                <emma enabled="true">
                                    <instr verbosity="${verbosity}"
                                           mode="overwrite"
                                           instrpath="${out.absolute.dir}/classes"
                                           outdir="${out.absolute.dir}/classes">
                                    </instr>
                                    <!-- TODO: exclusion filters on R*.class and allowing custom exclusion from
                                         user defined file -->
                                </emma>
                            </then>
                        </if>           
    </do-only-if-manifest-hasCode>
</target>

Indeed, this mechanism seems to be the right one as it mimics what eclipse does. But eclipse is able to know that the App depends on lib when compiling test. The only difference is that we exposed this relation manually in ant via the line (in project.properties)

tested.android.library.reference.1=../SDK_android

But it could be possible to do that automatically. I can't find the mechanism that google ant tools use to produce the librairy project path refid from the android.library.* statement in a project.properties. But if I could find this mechanism I could propagate this dependency in the test project, as eclipse does.

So I think the best would be to let google know that they have a patch to do, and temporarily keep the solution of exporting manually the dependency of th app project toward the lib project in order to compile the test project.

Can someone contact google about this bug ?

静若繁花 2024-12-29 03:40:43

这里发布的答案有点复杂。我不确定最近是否更改了这一点,但在 r15 中,可以简单地将以下行添加到其 project.properties 中,然后一切都会构建。您不需要修改任何构建脚本。

android.library.reference.1=../lib_project

我想它不会递归地查找库项目,因此如果您在正在测试的项目中引用它,则只需在测试项目中引用它即可。

The answers posted here are a little convoluted. I'm not sure if this was changed recently but in r15 one can simply add the following line to their project.properties and everything will build. You don't need to modify any of the build scripts.

android.library.reference.1=../lib_project

I guess its not looking for library projects recursively, so you just have to reference it in your test project if you're referencing it in the project you're testing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文