Export to GitHub

dexmaker - issue #2

dexcache == null (and no default could be found; consider setting the 'dexmaker.dexcache' system property)


Posted on Mar 23, 2012 by Happy Giraffe

What steps will reproduce the problem? 1. Android (3.0) + Mockito 1.9.1 (Snapshot) + dexmaker 2. Create Android test project and mock a object using mockito

What is the expected output? What do you see instead? Code should work but i get an error:

java.lang.IllegalArgumentException: dexcache == null (and no default could be found; consider setting the 'dexmaker.dexcache' system property) at com.google.dexmaker.DexMaker.generateAndLoad(DexMaker.java:359) at com.google.dexmaker.stock.ProxyBuilder.buildProxyClass(ProxyBuilder.java:252) at com.google.dexmaker.mockito.DexmakerMockMaker.createMock(DexmakerMockMaker.java:51) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:41) at org.mockito.internal.MockitoCore.mock(MockitoCore.java:41) at org.mockito.Mockito.mock(Mockito.java:1061) at org.mockito.Mockito.mock(Mockito.java:955) at nl.wowww.hallmark.kpp.android.tablet.test.CardSelection.testMockito(CardSelection.java:102) at java.lang.reflect.Method.invokeNative(Native Method) at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214) at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199) at android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTestCase2.java:186) at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169) at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154) at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:525) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1547)

What version of the product are you using? On what operating system? dexmaker20120305 + android sdk r17

Comment #1

Posted on Mar 26, 2012 by Happy Giraffe

When i add this line: System.setProperty("dexmaker.dexcache", "/sdcard"); Then i get this error: 03-26 14:58:17.261: E/dalvikvm(1322): Can't open dex cache '/data/dalvik-cache/sdcard@Generated1521942046.jar@classes.dex': No such file or directory

Comment #2

Posted on Apr 2, 2012 by Swift Giraffe

Hugo, it looks like the AppDataDirGuesser isn't guessing correctly in this case. Could you take a look?

Comment #3

Posted on Apr 25, 2012 by Helpful Horse

I am having the same problem, and AppDataDirGuesser is finding the right candidate (/data/data/com.my.app/cache), but the cache directory doesn't exist since my app doesn't use it, so the isWriteableDirectory(file) is false and it's not added as a result.

Comment #4

Posted on Apr 25, 2012 by Helpful Horse

The workaround is to add this to your test's setUp (you must make it an InstrumentationTestCase or subclass instead of just a TestCase if it's not already)

public void setUp() throws Exception {
    getInstrumentation().getTargetContext().getCacheDir();
}

This will make Android create the cache directory so that the AppDataDirGuesser will find it.

Comment #5

Posted on Jun 25, 2012 by Swift Giraffe

This issue is fixed in 524c023fb37b41e06b69f1b696100dd465acb353. Please confirm that it's working for you.

Comment #6

Posted on Aug 1, 2013 by Grumpy Hippo

I'm seeing this problem again after upgrading my phone to Android 4.3 - a load of tests suddenly started failing. Using mockito-core 1.9.5, dexmaker 1.0.

Adding this line to setUp() worked around it: System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath());

The proposed workaround: getInstrumentation().getTargetContext().getCacheDir(); had no effect.

Comment #7

Posted on Aug 1, 2013 by Swift Giraffe

It looks like DexMaker can't guess where the "cache" directory of the app is on Android 4.3: see https://code.google.com/p/dexmaker/source/browse/dexmaker/src/main/java/com/google/dexmaker/AppDataDirGuesser.java#63. It appears that the format of dalvik.system.PathClassLoader.toString has changed. For example, I'm getting the following on my Android 4.3 device:

dalvik.system.PathClassLoader[DexPathList[[zip file "/system/framework/android.test.runner.jar", zip file "/data/app/com.abc.def.tests-2.apk", zip file "/data/app/com.abc.def-2.apk"],nativeLibraryDirectories=[/data/app-lib/com.abc.def.tests-2, /data/app-lib/com.abd.def-2, /vendor/lib, /system/lib]]]

Options/fixes sorted in the order of increasing time spent before fix is live: 1. Set dexmaker.dexcache system property before your tests start (either in your tests' setUp or in a custom InstrumentationTestRunner): System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 2. Fix DexMaker's AppDataDirGuesser to understand the new toString format (in a backward compatible way). 3. Submit a patch to AOSP to make PathClassLoader expose the path in a structured, reliable way. 4. Submit a patch to AOSP to query the location of the current app's cache directory without referencing a Context.

Comment #8

Posted on Aug 21, 2013 by Quick Giraffe

Thanks for writing this issue. It also breaks with EasyMock for Android.

I hope some solution will come up, I use @klyu's number 1 solution and it's really ugly.

Comment #9

Posted on Aug 21, 2013 by Quick Kangaroo

Try polly.k's solution

Adding this line to setUp() worked around it: System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath());

I have successfully used this solution twice and it is working beautifully. All of my UI test cases extend a base class, so I just put it in the setUp() in the abstract base class and it works wonderfully.

public abstract class BaseInstrumentationTestCase extends ActivityInstrumentationTestCase2 {

@Override protected void setUp() throws Exception {

    super.setUp();

    System.setProperty( "dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath() );

    ...
}

}

Comment #10

Posted on Aug 26, 2013 by Helpful Horse

Note on #7 klyu's number one solution: if you are setting the system property in your InstrumentationTestRunner, remember to use getTargetContext instead of getContext, getTargetContext returns the context for the target application being instrumented, instead of the instrumentation context. http://developer.android.com/reference/android/app/Instrumentation.html#getTargetContext%28%29

public class InstrumentationTestRunner extends android.test.InstrumentationTestRunner { @Override public void onCreate(Bundle arguments) { super.onCreate(arguments); System.setProperty("dexmaker.dexcache", getTargetContext().getCacheDir().toString()); } ... }

Comment #11

Posted on Nov 13, 2013 by Quick Camel

We have just updated out Nexus 7 to 4.3 and are experiencing this issue. For now we are holding off on updating any other devices. Is any progress being made on this issue?

Comment #12

Posted on Nov 14, 2013 by Quick Giraffe

+mcclure

There is nothing special to wait for, a patch of dexmaker would make it easier, but meanwhile just use the dexmaker.dexcache property as proposed above.

Comment #13

Posted on Nov 14, 2013 by Quick Camel

We have created a library that is meant to be used both on android, and on a standard JVM. We want to run our unit tests in both environments. This prevents us from being able to set that property. We cannot turn our tests into InstrumentationTestCases, and cannot get a context to get the cacheDir from.

Comment #14

Posted on Nov 15, 2013 by Quick Rabbit

Here is a diff, a patch that patches this issue. This makes it work in 4.3.

This is #2.

Attachments

Comment #15

Posted on Oct 14, 2014 by Quick Giraffe

This appears to be the case in 4.4 as well. Any update on this?

Comment #16

Posted on Feb 1, 2015 by Helpful Monkey

I am having this issue as well, the suggested work around did the trick:

public void setUp() { System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath()); }

Comment #17

Posted on Feb 23, 2015 by Swift Camel

The solution proposed in this thread assumes that all tests have instrumentation available. Is it possible to avoid this error in a TestCase or AndroidTestCase?

Comment #18

Posted on Mar 9, 2015 by Happy Hippo

You could use something like this for TestCase

System.setProperty("dexmaker.dexcache", "/data/data/" + BuildConfig.APPLICATION_ID + ".test/cache");

Comment #19

Posted on Mar 24, 2015 by Happy Horse

It looks like the dexmaker project has moved to github, see: https://code.google.com/p/dexmaker/

In the central repository there are versions 1.1 and 1.2 published in March 2014 and December 2014: https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.google.dexmaker%22%20AND%20a%3A%22dexmaker%22

I've verified this "dexcache == null" issue still exists through version 1.2 - but only on certain devices. For example, a Galaxy S5 with Android 5.0 has the problem, and a Galaxy S4 with Android 4.4.2 does not.

I cloned the github repository (last commit March 12th 2015 - ca74669), and ran locally, and the problem has been fixed (there are also commits in the history that back this up). So once there is a 1.3 release, hopefully this problem is gone for good!

Anyone else wanting to run a local copy of 1.3-SNAPSHOT, here's how I did that (on a Mac, but other platforms should work too):

  • git clone https://github.com/crittercism/dexmaker.git
  • cd dexmaker
  • mvn install -Dmaven.test.skip=true
  • cp -R ~/.m2/repository/com/google/dexmaker $ANDROID_HOME/extras/android/m2repository/com/google
  • Then change version in app/build.gradle: androidTestCompile 'com.google.dexmaker:dexmaker:1.3-SNAPSHOT' -- Or pom.xml if using maven to build, or overwrite your libs/dexmaker.jar with ~/.m2/repository/com/google/dexmaker/dexmaker/1.3-SNAPSHOT/dexmaker-1.3-SNAPSHOT.jar if you are using eclipse/ant

Thanks, -Stan

Status: Accepted

Labels:
Type-Defect Priority-Medium