Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing a project that uses ActionBarSherlock

My setup:

  1. Library project: ActionBarSherlock
  2. Project
  3. 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).

like image 280
WarrenFaith Avatar asked Apr 25 '12 10:04

WarrenFaith


1 Answers

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.
like image 133
Graeme Avatar answered Oct 18 '22 03:10

Graeme