Can't Build and Run an Android Test Project Created Using "Ant Create Test-Project" When Tested Project Has Jars in Libs Directory

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

The problem is that there's a bug in the android ant build scripts that don't include the tested project's libs directory when compiling the tester project. If you try to get around this by copying the libs to the tester project's libs dir, you'll run into class verification problems at run time like I did, as pointed out by fadden.

The solution is to tweak the compile target originally in android's android_test_rules.xml to add <fileset dir="${tested.project.absolute.dir}/libs" includes="*.jar" /> to the <classpath> directive.

Here's the revised compile target. By adding it to the build.xml in your TESTER project, it will take precedence over the one in 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>

Unable to build android test project with ant

Okay, I spotted the problem.
I failed to mention that in ant.properties, I've changed the out.dir location to "../build". Because of this, the compiler did not know where to get the class files of the SampleApp when building the SampleAppTest. So one solution is to delete the out.dir entry in ant.properties, but I did not want that. I had to find a way to tell the compiler where to get these classes. The solutions I found was to override the "-compile" target in build.xml like so:

<property name="SampleApp.build.location" value="../build"/>
<target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile">
<do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
<!-- merge the project's own classpath and the tested project's classpath -->
<path id="project.javac.classpath">
<path refid="project.all.jars.path" />
<path refid="tested.project.classpath" />
</path>
<javac encoding="${java.encoding}"
source="${java.source}" target="${java.target}"
debug="true" extdirs="" includeantruntime="false"
destdir="${out.classes.absolute.dir}"
bootclasspathref="project.target.class.path"
verbose="${verbose}"
classpathref="project.javac.classpath"
fork="${need.javac.fork}">
<src path="${source.absolute.dir}" />
<src path="${gen.absolute.dir}" />
<compilerarg line="${java.compilerargs}" />
<classpath>
<!-- steff: we changed one line here !-->
<fileset dir="${SampleApp.build.location}/classes" includes="*"/>
</classpath>
</javac>

<!-- if the project is instrumented, intrument the classes -->
<if condition="${build.is.instrumented}">
<then>
<echo level="info">Instrumenting classes from ${out.absolute.dir}/classes...</echo>

<!-- build the filter to remove R, Manifest, BuildConfig -->
<getemmafilter
appPackage="${project.app.package}"
libraryPackagesRefId="project.library.packages"
filterOut="emma.default.filter"/>

<!-- define where the .em file is going. This may have been
setup already if this is a library -->
<property name="emma.coverage.absolute.file" location="${out.absolute.dir}/coverage.em" />

<!-- 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"
metadatafile="${emma.coverage.absolute.file}">
<filter excludes="${emma.default.filter}" />
<filter value="${emma.filter}" />
</instr>
</emma>
</then>
</if>

<!-- if the project is a library then we generate a jar file -->
<if condition="${project.is.library}">
<then>
<echo level="info">Creating library output jar file...</echo>
<property name="out.library.jar.file" location="${out.absolute.dir}/classes.jar" />
<if>
<condition>
<length string="${android.package.excludes}" trim="true" when="greater" length="0" />
</condition>
<then>
<echo level="info">Custom jar packaging exclusion: ${android.package.excludes}</echo>
</then>
</if>

<propertybyreplace name="project.app.package.path" input="${project.app.package}" replace="." with="/" />

<jar destfile="${out.library.jar.file}">
<fileset dir="${out.classes.absolute.dir}"
includes="**/*.class"
excludes="${project.app.package.path}/R.class ${project.app.package.path}/R$*.class ${project.app.package.path}/BuildConfig.class"/>
<fileset dir="${source.absolute.dir}" excludes="**/*.java ${android.package.excludes}" />
</jar>
</then>
</if>

</do-only-if-manifest-hasCode>
</target>

Android unit test using ant with library project

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 ?

JMock jars do not work inside Android test project (project doesn't build )

The problem is that JMock works using dynamic bytecode generation, but Dalvik isn't capable of doing that: dynamic bytecode generation is compiled down to JVM bytecode that's not supported by Dalvik; hence the error when converting.

Unfortunately, that means you can't use JMock on Android -- if you need it for testing, you'll have to run those tests on a JVM.

How to build an android test app with a dependency on another app using ant?

In /Users/mike/Projects/myapp/android/, assuming that the main app source is in a subdirectory called MyApp, run:

android create test-project -p MyAppTests -m ../MyApp -n MyAppTests

That will generate a test folder structure and appropriate Ant build files, so you can then do:

cd MyAppTests
ant run-tests

Running Android JUnit tests with Ant (with external dependencies): Target run-tests does not exist in the project XY

I managed to solve the problem by starting all over: reverted the build.xml to default as it was generated. I also transferred all external jar libraries to /libs library and thereafter I can build the tests.

NoClassDefFoundError when running Instrumentation test with ant

http://code.google.com/p/android/issues/detail?id=27608

I submitted the issue to Google and they uploaded a temporary fix. The fix will also be included in v18 release.

"project member x...@android.com, Today (34 minutes ago)
get the anttasks.jar from the bottom of http://tools.android.com/download to replace the one in your sdk."

The file to replace is at \Android\android-sdk\tools\lib\



Related Topics



Leave a reply



Submit