4

First of all, there are similar questions like here or here but I have neither some external libs nor a lib folder nor some included jars or something, so I wonder what I'm doing wrong by running Android Junit tests.

My project structure looks like this:
enter image description here

As you can see I have a separate project for Android JUnit tests. The testing class looks like this:

public class PersistenceManager {
    private static final String FILENAME = "kpzwien_storage";

    public static void persist(String data, Context context) throws IOException  {
        FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
        fos.write(data.getBytes());
        fos.close();
    }

    public static String read(Context context) throws IOException  {
        FileInputStream fis = context.openFileInput(FILENAME);
        StringBuffer fileContent = new StringBuffer("");

        byte[] buffer = new byte[1024];
        while (fis.read(buffer) != -1) {
            fileContent.append(new String(buffer));
        }

        return fileContent.toString();
    }
}

and here is its test case:

public class PersistenceManagerTest extends AndroidTestCase {

    private final String FILENAME_PREFIX = "test.";

    @Before
    public void setUp() {
        MockContentResolver resolver = new MockContentResolver();
        RenamingDelegatingContext renamingDelegatingContext = new RenamingDelegatingContext(new MockContext(), getContext(), FILENAME_PREFIX);
        Context context = new IsolatedContext(resolver, renamingDelegatingContext);

        setContext(context);
    }

    public void testPersistAndRead() throws IOException {
        String testData = "foobar";

        PersistenceManager.persist(testData, getContext());

        String result = PersistenceManager.read(getContext());

        assertEquals(testData, result);
    }
}

The manifest of the test project looks like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.devgems.android.kurzparkzonewien.androidtests"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="4" />

    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="net.devgems.android.kurzparkzonewien.activities" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <uses-library android:name="android.test.runner" />
    </application>
</manifest>

targetPackage is the application that the Instrumentation object will run against which is is identified by the package name assigned in its manifest file by the element. (Source: http://developer.android.com/guide/topics/manifest/instrumentation-element.html

The name of the package in my main project is

package="net.devgems.android.kurzparkzonewien.activities"

So it is exactly where targetPackage points to. If I run as "Android JUnit test", I always get a NoClassDefFoundError but why? Any ideas? I'm using ADT 20.0.3, Eclipse Juno.

At last here is the logcat output:

09-22 16:00:12.745: I/TestRunner(1528): java.lang.NoClassDefFoundError: net.devgems.android.kurzparkzonewien.controller.PersistenceManager 09-22 16:00:12.745: I/TestRunner(1528): at net.devgems.android.kurzparkzonewien.androidtests.PersistenceManagerTest.testPersistAndRead(PersistenceManagerTest.java:32) 09-22 16:00:12.745: I/TestRunner(1528): at java.lang.reflect.Method.invokeNative(Native Method) 09-22 16:00:12.745: I/TestRunner(1528): at java.lang.reflect.Method.invoke(Method.java:521) 09-22 16:00:12.745: I/TestRunner(1528): at junit.framework.TestCase.runTest(TestCase.java:154) 09-22 16:00:12.745: I/TestRunner(1528): at junit.framework.TestCase.runBare(TestCase.java:127) 09-22 16:00:12.745: I/TestRunner(1528): at junit.framework.TestResult$1.protect(TestResult.java:106) 09-22 16:00:12.745: I/TestRunner(1528): at junit.framework.TestResult.runProtected(TestResult.java:124) 09-22 16:00:12.745: I/TestRunner(1528): at junit.framework.TestResult.run(TestResult.java:109) 09-22 16:00:12.745: I/TestRunner(1528): at junit.framework.TestCase.run(TestCase.java:118) 09-22 16:00:12.745: I/TestRunner(1528): at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169) 09-22 16:00:12.745: I/TestRunner(1528): at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154) 09-22 16:00:12.745: I/TestRunner(1528): at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:430) 09-22 16:00:12.745: I/TestRunner(1528): at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447) 09-22 16:00:12.745: I/TestRunner(1528): ----- end exception -----

Community
  • 1
  • 1
Bevor
  • 8,396
  • 15
  • 77
  • 141
  • Shouldn't your test case class have a constructor? I don't see it. Like in the Android examples: http://developer.android.com/tools/testing/activity_test.html – Andy Res Sep 22 '12 at 16:21
  • I don't test an Activity. How should the constructor look like? – Bevor Sep 22 '12 at 17:08
  • By the way, there is no such constructor in AndroidTestCase. – Bevor Sep 23 '12 at 08:52
  • @Bevor just curious why are these seperate projects and if they are is the library for the development project added to the classpath of the test project ? i am not sure how would eclipse know where to find the developed "PersistanceManager" class if its located in a separate project . – Som Bhattacharyya Sep 25 '12 at 07:38
  • You need to create a different project for Android JUnit tests, because you can't mix them up with usual JUnit test due to different test runners. See documentation for more info. – Bevor Sep 25 '12 at 07:54
  • One thing that looks suspicious is that you have added "src/java/test" to the main project. Are you doing "Run As..." -> "Android JUnit Test" on your main project rather than the test project? Then that could be one cause of this problem. Double-check in "Run Configurations..." that you launch the tests with the InstrumentationTestRunner of the test project. – Martin Nordholts Sep 27 '12 at 09:07
  • The tests in main project (which is a Maven project) are absolutely independent from the tests in test project. These tests in main project are common JUnit tests. There is no Android test in there. The tests in main project are run with Run as -> JUnit test. I run the tests in test project with Run As -> Android JUnit test. By the way, there is some internal Android test called testAndroidTestCaseSetupProperly, and this test works, so that means that the test setup is basically correct. – Bevor Sep 27 '12 at 18:19

1 Answers1

2

I found the solution. But it's actually some kind of workaround because I can't image that I usually need to tinker like this (maybe someone knows a better solution?):

My main project is a Maven project, in this project I have to set configured the output folders from /bin... to /target/classes, target/test-classes and target/generated-sources. I've done that because otherwise my JUnit tests from main project would not find the latest code changes as long as I do not run mvn install.. If the output folders are target/..., I don't need to run mvn install to have the latest changes in my tests.
The problem is now that the Android test project doesn't find the compiled sources when they are stored in main project's target. When I set the output folder in main project to bin and run mvn install, the Android test project can find the classes now. I have to do this just once. When I set it back to target, both my Android tests still run and my main JUnit tests run. When I change the methods in the main project, the test project immediately recognize the changes, so that means it doesn't use binary jar or something (which is indeed very good, although I don't understand why it finds it now, although I set it back to target?).

[UPDATE]
Adding these two lines to main project's pom to build section solves the issue, so I don't need a workaround anymore.

    <outputDirectory>bin/classes</outputDirectory>
    <testOutputDirectory>bin/test-classes</testOutputDirectory>
Bevor
  • 8,396
  • 15
  • 77
  • 141