7

I get a java.lang.NoClassDefFoundError: android/util/Log error when I try to run my unit test project in eclipse.

Distilled down, my test code looks like this:

package com.randomtype.yycparking;

import junit.framework.TestCase;
import android.util.Log;

public class StallTests extends TestCase {  
    public void setUp() {
        Log.v("HI", "Fail");
    }

    public void testShouldParseIdFromTitle() {
        assertTrue(true);
    }
}

And the code throws an exception on the Log.v call. When I run the android project normally I don't get any exceptions around Log.

Full Stack Trace:

java.lang.NoClassDefFoundError: android/util/Log
    at com.randomtype.yycparking.StallTests.setUp(StallTests.java:11)
    at junit.framework.TestCase.runBare(TestCase.java:132)
    at junit.framework.TestResult$1.protect(TestResult.java:110)
    at junit.framework.TestResult.runProtected(TestResult.java:128)
    at junit.framework.TestResult.run(TestResult.java:113)
    at junit.framework.TestCase.run(TestCase.java:124)
    at junit.framework.TestSuite.runTest(TestSuite.java:243)
    at junit.framework.TestSuite.run(TestSuite.java:238)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.ClassNotFoundException: android.util.Log
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    ... 14 more

As pointed out by dtmilano, I wasn't running the unit tests as an Android JUnit Test. How can you tell the difference? Look for the little a like in the picture below:

Screen shot of a beside JUnit icon
(source: skitch.com)

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Gavin Miller
  • 43,168
  • 21
  • 122
  • 188

6 Answers6

4

Your tests should be in a separate Android Test Project (Project -> Android Tools -> New Android Project) and you should run them as Android JUnit Test (Run as -> Android JUnit Test).

Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
  • Check project properties (Java Build Path -> Libraries). Verify that android is there. – Diego Torres Milano Jan 11 '12 at 20:38
  • Wait a minute! I'm _not_ running it as an `Android JUnit Test`. I was accidentally running it as a `JUnit Test` – Gavin Miller Jan 11 '12 at 21:00
  • Do these tests have to extend something, or can they be just JUnit4 tests? – IgorGanapolsky Apr 08 '15 at 19:54
  • Take a look at https://developer.android.com/tools/testing/testing_android.html. Your tests cases should probably extend any of the specialized android test cases. – Diego Torres Milano Apr 08 '15 at 20:00
  • I do not have the option "Run as -> Android JUnit Test", this is probably from an of version of Android studio. However in the "Run/Debug Configuration window" I can see my test under the Android JUnit list configured to run with default JRE on my main package.... This still give exception on the Log class missing. Are you telling me I must run it as instrumental JUnit test? (aka inside an emulator) just because my class has logs? (even if that's the ONLY api used from Android) ? I can't believe there's no other solution... and no, I do not think `returnDefaultValues` is a solution. – Daniele Segato Feb 17 '17 at 08:51
  • What does people use? Roboeletric? – Daniele Segato Feb 17 '17 at 09:08
  • Then don't use `Log` in your unit tests, just use `System.out.println()` – Diego Torres Milano Feb 17 '17 at 15:41
  • This is not useful. Answer by @ahsiu with reference to tools.android.com should be accepted: set in build.gradle in testOptions {unitTests.returnDefaultValues = true} – Ewoks Sep 10 '18 at 10:55
2

Today when running the unit tests in my project, I hit this same error - over 100 of my unit tests were suddenly failing, even though they were working a week ago (without me doing any changes). The solution was to restart Android Studio. I think there's a bug in the 3.5.x versions of Android Studio where over time it can lose the configuration for running unit tests and will start throwing errors such as this one.

Carl Anderson
  • 3,446
  • 1
  • 25
  • 45
1

Same mistake here, other reason...

My test class was in an anonymous package but it was inconistent with AndroidManifest.xml:

<instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="micharg.nameanimalthing" />

[same answer posted here]

Community
  • 1
  • 1
Mike Argyriou
  • 1,250
  • 2
  • 18
  • 30
1
 android {
  // ...
  testOptions { 
    unitTests.returnDefaultValues = true
  }
}

reference http://tools.android.com/tech-docs/unit-testing-support#TOC-Method-...-not-mocked.-

i find my issue: notify your build.gradle file ,you should set the compileSdkVersion equal 23 and the same as targetSdkVersion, it work well.

ahsiu
  • 123
  • 1
  • 6
1

I ran into this issue in the context of running JUnit tests for Android with mocks for the Log methods, since my unit tests should not have relied on Android's own implementation.

So I had mocks in test/java/android/util/Log.java – all except the Log.v method. After adding the v method in the mocks, everything worked again.

package android.util;

public class Log {
    public static int d(String tag, String msg) {
        System.out.println("DEBUG: " + tag + ": " + msg);
        return 0;
    }

    public static int i(String tag, String msg) {
        System.out.println("INFO: " + tag + ": " + msg);
        return 0;
    }

    public static int w(String tag, String msg) {
        System.out.println("WARN: " + tag + ": " + msg);
        return 0;
    }

    public static int e(String tag, String msg) {
        System.out.println("ERROR: " + tag + ": " + msg);
        return 0;
    }

    public static int v(String tag, String msg) {
        System.out.println("VERB: " + tag + ": " + msg);
        return 0;
    }
}
slhck
  • 36,575
  • 28
  • 148
  • 201
1

It is year 2023. Eclipse is no longer supported for Android development. I am using the latest & greatest Android Studio (2022.2.1 Patch 2) with Android SDK 33.

JUnit test are in the same module/library as the class to be tested and they are not in a separate module/library. Therefore, using mocks for the Log methods as proposed here, is not practical for me.

Especially when I already had my JUnit tests working without such mocks, before updating my environment from Java 8 to 17, using:

logMockedStatic = Mockito.mockStatic(Log.class);

So... after some troubleshooting, I discovered that the root cause of this newly introduced java.lang.NoClassDefFoundError: android/util/Log (after updating JDK8 to JDK17), was the classpath in my Run/Debug Configurations > JUnit > Build and run section:

I already had -cp MyProj.myLib.main in there, but I needed to add android.jar to eliminate this error. Here is how I did it:

  1. File > Project Structure > SDK Location (find exact path to android.jar)
  2. Run/Debug Configurations > JUnit > Build and run > Modify options: check Modify classpath.
  3. In the newly added box labeled 'Modify classpath' (as a result of last step), click + to add C:\Users\Me\AppData\Local\Android\Sdk\platforms\android-33\android.jar

Works now like a charm.

Introspective
  • 554
  • 2
  • 5
  • 13