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:
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.
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 :
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”).
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)
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 ?