title: Custom Android sdk and unit test on Android Studio
body: <p>I am trying to do a unit test with custom Android Sdk in Android Studio 2.2.2 with com.android.tools.build:gradle:2.2.2. but I keep getting some errors and cannot get through them, so I would like to ask for your help. Let me explain what I’ve done and tried to see if you can figure it out and help me.</p>
  
  <p>I did a custom android.jar extracting classes from Nexus 5x with android 6 (sdk 23). This jar contains hidden methods and internal classes.</p>
  
  <h3>COMPLETE CUSTOM SDK</h3>
  
  <p>The first attempt was creating a complete SDK. For that I downloaded the SDK, installed version 23 and replaced it in new_sdk/platform/android-23/android.jar with my custom jar.</p>
  
  <p>In Android Studio I can execute tasks like assemble or install for generate apk, but when I execute a unitTest or any task that contains the ':app:mockableAndroidJar' task I get the following error:  </p>
  
  <pre><code>Execution failed for task ':app:mockableAndroidJar' &gt; java.lang.NullPointerException (no error message)
  </code></pre>
  
  <p>I think that I get this error because the custom sdk contains implementations in the methods and no Stubs like original android.jar.</p>
  
  <h3>CUSTOM SDK LIKE JAR DEPENDENCY</h3>
  
  <p>The second attempt I’ve tried is using the original sdk and add the extended custom sdk like dependency jar. In this case I add the jar in app build.gradle like:</p>
  
  <pre><code>dependencies {
     ...
     provided files('libs/android-full-23-nexus5x.jar')
     ...
  }
  </code></pre>
  
  <p>AndroidStudio shows compilation error for hide methods and constants because can't resolve symbols, but it works for internal classes.</p>
  
  <p><a href="https://i.stack.imgur.com/COFQs.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/COFQs.png" alt="enter image description here"></a></p>
  
  <p>The problem is that Android Sdk overrides my custom jar. To fix this I’ve changed in <em>app.iml</em> the order of dependencies so:</p>
  
  <pre><code>...
  &lt;orderEntry type="library" exported="" name="android-full-23-nexus5x" level="project" /&gt;
  &lt;orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK"/&gt;
  ...
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/8Rjar.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8Rjar.png" alt="enter image description here"></a></p>
  
  <p>This is a problem, because in each gradle sync <em>app.iml</em> is reordered.</p>
  
  <p>Now, assemble or install tasks failed in compilation time too. </p>
  
  <pre><code>/.../MainActivity.java:63: error: cannot find symbol
      boolean aa = TelephonyManager.EMERGENCY_ASSISTANCE_ENABLED;
                                   ^
      symbol:   variable EMERGENCY_ASSISTANCE_ENABLED
      location: class TelephonyManager
  /.../MainActivity.java:68: error: cannot find symbol
      String result = tm.getNai();
                        ^
      symbol:   method getNai()
      location: variable tm of type TelephonyManager
  2 errors
  :app:compileDebugJavaWithJavac FAILED
  </code></pre>
  
  <p>That is solved adding in <em>root</em> build.gradle :</p>
  
  <pre><code>allprojects {
     ...
  gradle.projectsEvaluated {
      tasks.withType(JavaCompile) {
          options.compilerArgs.add("-Xbootclasspath/p:app/libs/android-full-23-nexus5x.jar")
         }
      }
  }
  </code></pre>
  
  <p>After sync, clean and rebuild, assemble and install tasks works, only for actual BuildType but it works.</p>
  
  <p>Now, I execute a unitTest without Mocks like:</p>
  
  <pre><code>public class EmailValidatorTest {
      @Test
      public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
          assertTrue(EmailValidator.isValidEmail("name@email.com"));
      }
  }
  </code></pre>
  
  <p>This works ok, but when I need to execute a unitTest with mocks this fails:</p>
  
  <pre><code>public class MockUnitTest {
  
      private static final String FAKE_STRING = "my_app_name";
  
      @Mock
      Context mMockContext;
  
      @Test
      public void readStringFromContext_LocalizedString() {
          // Given a mocked Context injected into the object under test...
          when(mMockContext.getString(R.string.app_name)).thenReturn(FAKE_STRING);
          ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext);
  
          // ...when the string is returned from the object under test...
          String result = myObjectUnderTest.getHelloWorldString();
  
          // ...then the result should be the expected one.
          assertThat(result, is(FAKE_STRING));
      }
  }
  </code></pre>
  
  <p>. </p>
  
  <pre><code>java.lang.NullPointerException
            at android.content.Context.getString(Unknown Source)
            at com.caseonit.pruebamockito.MockUnitTest.readStringFromContext_LocalizedString(MockUnitTest.java:32)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
            at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
            at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
            at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
            at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
            at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
            at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
            at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
            at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
            at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
            at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
            at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
            at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
            at org.mockito.internal.runners.SilentJUnitRunner.run(SilentJUnitRunner.java:39)
            at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
            at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:103)
            at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
            at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
            at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
            at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
            at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
  </code></pre>
  
  <p>I have discovered that if I remove from the file <em>app.iml</em> the line <code>&lt;orderEntry type="library" exported="" name="android-full-23-nexus5x" level="project" /&gt;</code> unitTest with mock works and assemble task keeps working, the problem is that AndroidStudio shows error because can't resolve symbols.
  This will also not allow mock hidden methods.</p>
  
  <h3>Executing unit test from command line</h3>
  
  <p>When AndroiStudio executes a unitTest the command is:</p>
  
  <pre><code>/Library/Java/JavaVirtualMachines/jdk1.8.0_102.jdk/Contents/Home/bin/java -ea -Didea.launcher.port=7537 "-Didea.launcher.bin.path=/Applications/Android Studio.app/Contents/bin" -Didea.junit.sm_runner -Dfile.encoding=UTF-8 -classpath "/Applications/Android Studio.app/Contents/lib/idea_rt.jar: ... :.../app/libs/android-full-23-nexus5x.jar: ... :.../build/generated/mockable-android-23.jar" com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 com.caseonit.pruebamockito.MockUnitTest,readStringFromContext_LocalizedString
  </code></pre>
  
  <p>and the result is the same error from AndroidStudio, but if I change the <strong>classpath</strong> parameter and set the <em>android-full-23-nexus5x.jar</em> after **mockable-android-23.jar* the result is correct.</p>
  
  <p>So, my question is: Is it posible to change classpath for unitTest? I have tried </p>
  
  <pre><code>android.unitTestVariants.all { variant -&gt;
      variant.javaCompile.classpath.minus(['/.../app/libs/android-full-23-nexus5x.jar'])
  }
  </code></pre>
  
  <p>or similar, but none works.
  Do you have any idea or suggestion?
  Thank you very much. 
  Best regards,</p>