Testing a project that uses ActionBarSherlock

actionbarsherlock, android, android-library, android-testing, ant

Solution

There are lots of different bits of information floating around regarding using `Library` projects since ADT 17 broke/fixed everything (depending on wether you're currently banging your head against your desk).

First of all, please note the difference between `Library` and "library" where `Library` is a noun as decreed by the Android team. I'm also using `Referencing` project which describes a project which uses a `Library` project.

ie, A `Referencing` project uses a `Library` project.

non `Library` "library" Projects

In normal Java development it's possible to link projects in Eclipse where one is dependent on the source of the other. I believe this approach has the effect of using the library projects source(s) as the source for the referencing project. This means that library projects source is in scope while compiling the referencing project. The library project classes are built at the same time as those of the referencing project.

When building for use in most situations this works perfectly well as all of the classes are built and then packaged in JARs or WARs or whatever.

Library Projects

A competing (not a mix and match) approach to library projects are the Android teams `Library` projects:

An Android project marked as being a `Library` Project will compile and build it's sources into a `jar` file in its `bin` directory (after a clean/build command). Any `Referencing` projects automatically importing this `jar` and gaining access to the `Library` projects functionality. You can see this relationship by looking inside the Java Library `Android Dependencies` in the Package Explorer.

Alongside the class dependency resolution the resource are also being directly referenced and compiled into `R.java` files inside of the `Referencing` projects `gen` directory.

The new `ADT` introduced problems to peoples set up's because it added "support" for including jars which were referenced by the `Library` project:

Pre ADT 17

The `Library` project had a jar added to it's build path. The `Referencing` project could also have the jar added to its own build path.

ADT 17 onwards

Dealing With Dependencies

After ADT 17 `Library` projects which dynamically referenced their own jars started to behave strangely. It wasn't simply a case of including the same dependent reference in your `Referencing` project to keep the jar visible in both scopes. This now resulted in strange duplication of included classes.

Unfortunately simply removing the library from the `Referencing` or `Library` project (so only one link was present) then confused eclipse, it could no longer could see the jar from the scope of the Project using it.

To fix this you need to place the `Library` projects jars in the `/libs` directory - this can be a pain in the rear if you jars are on disperate places on your harddrive. These jars will then automatically be used in your `Library` and `Referencing` projects.

So, to move past ADT 17:

- Remove any jar files not being used as a source in the current projects scope (whether this be your `Library` or `Referencing` project).

- Remove none "library" projects from your `Library` project (instead compile them into jars).

- Remove external jars from your `Library` project, copy them to the `libs` directory instead.

Problem

My setup: - Library project: ActionBarSherlock - Project - Test project My project has the library project linked as a library project. It compiles and runs fine. Now I try to test my application using a normal test project. Running the tests in eclipse works perfect. If I try to run the tests using ant, the test project doesn't even compile: ``` [javac] LoginActivityTest.java:9: cannot access com.actionbarsherlock.app.SherlockActivity [javac] class file for com.actionbarsherlock.app.SherlockActivity not found [javac] public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> { [javac] ^ [javac] LoginActivityTest.java:25: cannot find symbol ``` Building via eclipse works perfect and the test runs perfect, too. If I link the library project to my test project, it compiles with ant but the tests fails. ``` [exec] Error in testSuiteConstructionFailed: [exec] java.lang.RuntimeException: Exception during suite construction [exec] at android.test.suitebuilder.TestSuiteBuilder$FailedToCreateTests.testSuiteConstructionFailed(TestSuiteBuilder.java:238) [exec] at java.lang.reflect.Method.invokeNative(Native Method) [exec] at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169) [exec] at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154) [exec] at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:537) [exec] at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1551) [exec] Caused by: java.lang.reflect.InvocationTargetException [exec] at java.lang.reflect.Constructor.constructNative(Native Method) [exec] at java.lang.reflect.Constructor.newInstance(Constructor.java:417) [exec] at android.test.suitebuilder.TestMethod.instantiateTest(TestMethod.java:87) [exec] at android.test.suitebuilder.TestMethod.createTest(TestMethod.java:73) [exec] at android.test.suitebuilder.TestSuiteBuilder.addTest(TestSuiteBuilder.java:262) [exec] at android.test.suitebuilder.TestSuiteBuilder.build(TestSuiteBuilder.java:184) [exec] at android.test.InstrumentationTestRunner.onCreate(InstrumentationTestRunner.java:371) [exec] at com.zutubi.android.junitreport.JUnitReportTestRunner.onCreate(JUnitReportTestRunner.java:90) [exec] at android.app.ActivityThread.handleBindApplication(ActivityThread.java:3891) [exec] at android.app.ActivityThread.access$1300(ActivityThread.java:122) [exec] at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1184) [exec] at android.os.Handler.dispatchMessage(Handler.java:99) [exec] at android.os.Looper.loop(Looper.java:137) [exec] at android.app.ActivityThread.main(ActivityThread.java:4340) [exec] at java.lang.reflect.Method.invokeNative(Native Method) [exec] at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) [exec] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) [exec] at dalvik.system.NativeStart.main(Native Method) [exec] Caused by: java.lang.NoClassDefFoundError: com.myproject.android.app.activities.LoginActivity [exec] at com.myproject.android.app.test.LoginActivityTest.<init>(LoginActivityTest.java:18) [exec] ... 19 more ``` My test class: ``` public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> { private LoginActivity mActivity; private EditText mTextUserName; private EditText mTextUserPassword; public LoginActivityTest() { // the super call is line 18 (see stack trace above) super("com.myproject.android.app.activities", LoginActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); mActivity = getActivity(); mTextUserName = (EditText) mActivity.findViewById(com.myproject.android.app.R.id.login_activity_username); mTextUserPassword = (EditText) mActivity.findViewById(com.myproject.android.app.R.id.login_activity_password); } public void testPreConditions() { assertTrue("Activity is null!", mActivity != null); } public void testLogin() throws Throwable { mActivity.runOnUiThread(new Runnable() { public void run() { mTextUserName.setText("username"); mTextUserPassword.setText("password"); } }); sendKeys(KeyEvent.KEYCODE_ENTER); } } ``` Some ideas how I can fix this? Update: it looks like the ant build/test is still a mess. According to this blog entry about testing a library project most of the 7 listed issues will be fixed in the next ADT release (ADT r20).

Original source