How to use an android dependency in unit tests? - android

I'm currently trying out TDD, but cannot get my head around how to use android dependencys in my unit tests.
I want to parse the JSON response of the PONS API to an Object.
To test my Jsonparser, I tried to create a mock a spy, or just to a normal instance of the JsonReader the android.utils.JsonReader, which i then pass to my parser.
#Mock
private var reader : JsonReader = JsonReader(BufferedReader(FileReader(fileName)))
#Before
fun setUp(){
MockitoAnnotations.initMocks(this)
}
#Test
fun parseTest() {
val response = ResponseParser.parse(reader)
val entry : response.Entry = response.getEntry(0)
assertThat(entry.strings_displayed[0].get(0).first, `is`("Haus (Wohnhaus, Heim)"))
assertThat(entry.strings_displayed[0].get(0).second, `is`("casa"))
}
however none of my attempts has yielded the desired output. As of now i'm not able to use the JsonReader class. All i get is this error message (which of cause has been googled)
java.lang.RuntimeException: Method beginObject in android.util.JsonReader not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.util.JsonReader.beginObject(JsonReader.java)
at com.huckebrink.remindyct.Data.PONSRequestParser$Companion.readJsonString(PONSRequestParser.kt:23)
at com.huckebrink.remindyct.Data.PONSRequestParser$Companion.parse(PONSRequestParser.kt:13)
at com.huckebrink.remindyct.ParsingUnitTest.parseTest(ParsingUnitTest.kt:47)
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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
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.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Well, my recommendation is to try to keep your Unit Test level without depending on the Android Framework, it makes everything easy if you can test only with Kotlin pure at Unit level and leave more complex tests for the Integration level.
Sometimes it's not so easy if the app is coupled, so, you can use some library as Robolectric to have the Android Framework working partially in your Unit Tests.
Search for: "Robolectric unit tests" to get examples. Good luck
UPDATE:
From the Android documentation https://developer.android.com/training/testing/unit-testing
Local tests: Unit tests that run on your local machine only. These tests are compiled to run locally on the Java Virtual Machine (JVM) to minimize execution time. If your tests depend on objects in the Android framework, we recommend using Robolectric. For tests that depend on your own dependencies, use mock objects to emulate your dependencies' behavior.
UPDATE 2:
JSON parsing should be part of the instrumented/integration level of tests, anyway, if you want the dependencies to use JsonParing on test directory you can add:
testCompile ‘org.json:json:20140107’

Related

Mockito 2 for Android Instrumentation test : Could not initialize plugin: interface org.mockito.plugins.MockMaker

I'm using Mockito 2 and Espresso for Unit tests, and met a problem trying to use Mockito 2 in Instrumentation test. While running the test, I'm getting this error
java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.MockMaker (alternate: null)
at org.mockito.internal.configuration.plugins.PluginLoader$1.invoke(PluginLoader.java:74)
at java.lang.reflect.Proxy.invoke(Proxy.java:913)
at $Proxy5.isTypeMockable(Unknown Source)
at org.mockito.internal.util.MockUtil.typeMockabilityOf(MockUtil.java:29)
at org.mockito.internal.util.MockCreationValidator.validateType(MockCreationValidator.java:22)
at org.mockito.internal.creation.MockSettingsImpl.validatedSettings(MockSettingsImpl.java:232)
at org.mockito.internal.creation.MockSettingsImpl.build(MockSettingsImpl.java:226)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:64)
at org.mockito.Mockito.mock(Mockito.java:1864)
at org.mockito.Mockito.mock(Mockito.java:1777)
at com.armop.insight.views.activity.InsightActivityTest.testUserResultReturnsEmpty(InsightActivityTest.kt:66)
at java.lang.reflect.Method.invoke(Native Method)
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 android.support.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:433)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
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.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
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.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:58)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:369)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2075)
Caused by: java.lang.IllegalStateException: Failed to load interface org.mockito.plugins.MockMaker implementation declared in sun.misc.CompoundEnumeration#5ea25e5
at org.mockito.internal.configuration.plugins.PluginInitializer.loadImpl(PluginInitializer.java:54)
at org.mockito.internal.configuration.plugins.PluginLoader.loadPlugin(PluginLoader.java:57)
at org.mockito.internal.configuration.plugins.PluginLoader.loadPlugin(PluginLoader.java:44)
at org.mockito.internal.configuration.plugins.PluginRegistry.<init>(PluginRegistry.java:21)
at org.mockito.internal.configuration.plugins.Plugins.<clinit>(Plugins.java:18)
at org.mockito.internal.configuration.plugins.Plugins.getMockMaker(Plugins.java:34)
at org.mockito.internal.util.MockUtil.<clinit>(MockUtil.java:24)
... 38 more
Caused by: org.mockito.exceptions.base.MockitoInitializationException:
Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)
IMPORTANT INFORMATION FOR ANDROID USERS:
The regular Byte Buddy mock makers cannot generate code on an Android VM!
To resolve this, please use the 'mockito-android' dependency for your application:
http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22mockito-android%22%20g%3A%22org.mockito%22
Java : 0.9
JVM vendor name : The Android Project
JVM vendor version : 2.1.0
JVM name : Dalvik
JVM version : 0.9
JVM info : null
OS name : Linux
OS version : 3.18.91+
at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.<init>(InlineByteBuddyMockMaker.java:171)
at java.lang.Class.newInstance(Native Method)
at org.mockito.internal.configuration.plugins.PluginInitializer.loadImpl(PluginInitializer.java:49)
... 44 more
Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;
at net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm$ForLegacyVm.resolve(ByteBuddyAgent.java:940)
at net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm.resolve(ByteBuddyAgent.java:925)
at net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:352)
at net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:320)
at net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:306)
at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.<clinit>(InlineByteBuddyMockMaker.java:101)
... 46 more
Caused by: java.lang.ClassNotFoundException: Didn't find class "java.lang.management.ManagementFactory" on path: DexPathList[[zip file "/system/framework/android.test.runner.jar", zip file "/system/framework/android.test.mock.jar", zip file "/data/app/com.armop.debug.test-GWx-9OMGi9FTj01c1acroQ==/base.apk", zip file "/data/app/com.armop.debug-28ywc-fJ-zzWAgMPBESlGQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.armop.debug.test-GWx-9OMGi9FTj01c1acroQ==/lib/x86, /data/app/com.armop.debug-28ywc-fJ-zzWAgMPBESlGQ==/lib/x86, /data/app/com.armop.debug.test-GWx-9OMGi9FTj01c1acroQ==/base.apk!/lib/x86, /data/app/com.armop.debug-28ywc-fJ-zzWAgMPBESlGQ==/base.apk!/lib/x86, /system/lib, /vendor/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:125)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 52 more
And here is the test code.
#Test
fun testUserResultReturnsEmpty() {
val userMock = Mockito.mock(UserModel::class.java)
Mockito.`when`(ArmOpApplication.getUserFromPrefs()).thenReturn(userMock)
mActivityRule.launchActivity(Intent())
mCountDownLatch.await(3000, TimeUnit.MILLISECONDS)
assertNotNull(mActivityRule.activity.mInsightCategories)
assertNull(mActivityRule.activity.mData)
assertNull(mActivityRule.activity.insightsRecyclerView.adapter)
}
I've googled for more information and found out, that I need to use mockito-android instead of mockito core, and added those lines in application's build.gradle file
androidTestImplementation "org.mockito:mockito-android:${libMockitoAndroidVersion}"
androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0'
where libMockitoAndroidVersion = 2.16.0
Also, I've added org.mockito.plugins.MockMaker file into the androidTest resource directory to work with Kotlin's classes.
Is there any way to fix this issue? Any help will be appreciated.
Working with Android replace
androidTestImplementation "org.mockito:mockito-core:$mockito_core_version"
androidTestImplementation "org.mockito:mockito-inline:$mockito_core_version"
for
androidTestImplementation "org.mockito:mockito-android:$mockito_core_version"
My version was: $mockito_core_version = '2.28.2'
I was having this issue and none of the solutions here worked for me. My problem was that I was mixing both mockito libraries
//BAD CODE
testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0"
testImplementation "org.mockito:mockito-android:3.3.3"
//GOOD CODE - just use one
testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0"
I've got similar problem. I my case that was invalid declaration in resource/mockito-extensions/org.mockito.plugins.MockMaker file. During some refactoring process IDE replaced correct value:
mock-maker-inline
with this one:
infrastructure-maker-inline
I've noticed that accidental change while reviewing the commit diff because it didn't look suspicious for first look.
This helped me
androidTestImplementation("org.koin:koin-test:1.0.2")
{ exclude("org.mockito", "mockito-inline") }
androidTestImplementation("org.mockito:mockito-android:2.24.5")
Koin represents some library that contain org.mockito
In the stacktrace I found this:
Caused by: java.lang.IllegalStateException: Failed to load interface org.mockito.plugins.MockMaker implementation declared in sun.misc.CompoundEnumeration
Enlighted by this issue(#824 Exception when using mock-maker-inline), I resolved the same problem by adding tools.jar to my classpath in intellij
add tools.jar to classpath
From the stack trace it seems like you are using the inline Byte Buddy mock maker which does not work on Android. Make sure that you have not included it transitively somehow as both plugins being available would load the one that is added to the class path first.
In my case it worked with adding mockito kotlin dependency and i think it would be better to stay away from inline library, because as i read somewhere it is just a dependency to check final class mocking issue solution and later it will be stopped of updating
use these 2 dependencies
testImplementation 'org.mockito:mockito-core:2.23.0'
testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0"

Custom Android sdk and unit test on Android Studio

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.
I did a custom android.jar extracting classes from Nexus 5x with android 6 (sdk 23). This jar contains hidden methods and internal classes.
COMPLETE CUSTOM SDK
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.
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:
Execution failed for task ':app:mockableAndroidJar' > java.lang.NullPointerException (no error message)
I think that I get this error because the custom sdk contains implementations in the methods and no Stubs like original android.jar.
CUSTOM SDK LIKE JAR DEPENDENCY
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:
dependencies {
...
provided files('libs/android-full-23-nexus5x.jar')
...
}
AndroidStudio shows compilation error for hide methods and constants because can't resolve symbols, but it works for internal classes.
The problem is that Android Sdk overrides my custom jar. To fix this I’ve changed in app.iml the order of dependencies so:
...
<orderEntry type="library" exported="" name="android-full-23-nexus5x" level="project" />
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK"/>
...
This is a problem, because in each gradle sync app.iml is reordered.
Now, assemble or install tasks failed in compilation time too.
/.../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
That is solved adding in root build.gradle :
allprojects {
...
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add("-Xbootclasspath/p:app/libs/android-full-23-nexus5x.jar")
}
}
}
After sync, clean and rebuild, assemble and install tasks works, only for actual BuildType but it works.
Now, I execute a unitTest without Mocks like:
public class EmailValidatorTest {
#Test
public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
assertTrue(EmailValidator.isValidEmail("name#email.com"));
}
}
This works ok, but when I need to execute a unitTest with mocks this fails:
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));
}
}
.
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)
I have discovered that if I remove from the file app.iml the line <orderEntry type="library" exported="" name="android-full-23-nexus5x" level="project" /> 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.
Executing unit test from command line
When AndroiStudio executes a unitTest the command is:
/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
and the result is the same error from AndroidStudio, but if I change the classpath parameter and set the android-full-23-nexus5x.jar after **mockable-android-23.jar* the result is correct.
So, my question is: Is it posible to change classpath for unitTest? I have tried
android.unitTestVariants.all { variant ->
variant.javaCompile.classpath.minus(['/.../app/libs/android-full-23-nexus5x.jar'])
}
or similar, but none works.
Do you have any idea or suggestion?
Thank you very much.
Best regards,

Firebase + RoboElectric: java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist

I am using Firebase in our android application for remote config. Below is the initialization done in my application class onCreate method:
FirebaseRemoteConfig remoteConfig = FirebaseRemoteConfig.getInstance();
FirebaseRemoteConfigSettings settings = new FirebaseRemoteConfigSettings.Builder()
.setDeveloperModeEnabled(BuildConfig.DEBUG)
.build();
remoteConfig.setConfigSettings(settings);
setFirebaseDefault();
Map<String, Object> defaults = new HashMap<>();
defaults.put(FirebaseConstantsKt.BREAKING_NEWS, "");
defaults.put(FirebaseConstantsKt.ENABLE_BREAKING_NEWS, false);
FirebaseRemoteConfig.getInstance().setDefaults(defaults);
As per this answer my build.gradle file also has the following line in it:
apply plugin: 'com.google.gms.google-services'
When I run the application it works fine but when I try to run my Roboelectric test case it crashes with following exception:
java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
at com.google.firebase.remoteconfig.FirebaseRemoteConfig.getInstance(Unknown Source)
at com.woi.apppackage.android.MyApplication.initFirebase(MyApplication.java:225)
at com.woi.apppackage.android.MyApplication.onCreate(MyApplication.java:107)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:140)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:433)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:240)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
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.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
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)
The test has nothing to do with Firebase. If I comment out the Firebase code in onCreate the test runs fine. I think I am missing something in my initialization of Firebase
This may be caused by Firebase Crash. The current implementation of it creates a process called background_crash. An instance of your Application class is created for each process of your app, including background_crash. This is described in the documentation.
Try adding this code to only initialize Remote Config when in your main process:
if (FirebaseApp.getApps(this).isEmpty()) {
// In the crash process
} else {
// Not in crash process
// Init Remote Config here
}
I think there's a bug with Firebase that is being called in Application level. I have the same issue with Firebase Database and got it resolved by moving my Firebase codes in my activity class, (SplashScreen in my case).
I suggest try doing the same. :)
You can do
if (FirebaseApp.getApps(context).isEmpty()) {
FirebaseApp.initializeApp(context);
}
just before you initialize firebase. This can happen if Firebase wasn't properly initialized (maybe because of an internal exception)

When unit testing Call object is null whenever retrofit2 request is made

Earlier my project was using Retrofit and everything seems working fine when I wrote unit testing. Now we upgraded to Retrofit 2.0 using compile 'com.squareup.retrofit2:retrofit:2.0.0'.
We are doing unit testing using Robolectric.
Here is the test we wrote for earlier Retrofit version.
#Test
public void testButton() throws Exception {
button.setText("www.google.com");
button.performClick();
Mockito.verify(mockApiservice).getLinkDetails(requestArgumentCaptor.capture());
assertThat(requestArgumentCaptor.getValue()).isEqualTo("www.google.com");
assertThat(button.getVisibility()).isEqualTo(View.GONE);
}
Now when we upgraded to Retrofit 2.0, and the button click real code changes to
Call<MyPOJO> callObj = ApiService.getLinkDetails(encodedUrlString);
callObj.enqueue(this);
The test is getting failed even though I changed the test code to -
#Test
public void testButton() throws Exception {
button.setText("www.google.com");
button.performClick();
assertThat(button.getVisibility()).isEqualTo(View.GONE);
}
The error which I'm getting now is -
java.lang.NullPointerException at callObj.enqueue(this);
which means that callObj is null
So 2 most important questions -
Why am I getting the NPE in the real code?
How can I change my test code to make mock request to the API and get the mock response?
I searched everywhere but I didn't got any clue.
Please help me. Any input is greatly appreciated.
Logcat -
java.lang.NullPointerException
at com.myapp.MyFragment.onButtonClick(MyFragment.java:428)
at com.myapp.fragment.MyFragment.access$100(MyFragment.java:62)
at com.myapp.fragment.MyFragment$3.onClick(MyFragment.java:148)
at android.view.View.performClick(View.java:4756)
at com.myapp.MyFragmentTest.testButton(MyFragmentTest.java:122)
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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
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.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
I might have figured it out - it looks like you're calling getLinkDetails as a static method, but you need to do it like this:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://url.com/")
.build();
ApiService service = retrofit.create(ApiService.class);
Call<MyPOJO> callObj = service.getLinkDetails(encodedUrlString);
callObj.enqueue(this);
You can reuse the Retrofit object and the service object, but not the Call.
Retrofit 2 documentation: http://square.github.io/retrofit/

How to load .so when using Robolectric?

W/Environment: EXTERNAL_STORAGE undefined; falling back to default
java.lang.UnsatisfiedLinkError: com.autonavi.amap.mapcore.MapCore.nativeNewInstance(Ljava/lang/String;)J
at com.autonavi.amap.mapcore.MapCore.nativeNewInstance(Native Method)
at com.autonavi.amap.mapcore.MapCore.<init>(MapCore.java:62)
at com.amap.api.mapcore.AMapDelegateImpGLSurfaceView.<init>(AMapDelegateImpGLSurfaceView.java:356)
at com.amap.api.mapcore.AMapDelegateImpGLSurfaceView.<init>(AMapDelegateImpGLSurfaceView.java:318)
at com.amap.api.mapcore.ak.a(MapFragmentDelegateImp.java:123)
at com.amap.api.maps.MapView.onCreate(MapView.java:131)
at com.e.activity.DriverReleaseActivity.initData(DriverReleaseActivity.java:179)
at com.e.base.BaseActivity.onCreate(BaseActivity.java:29)
at android.app.Activity.performCreate(Activity.java:5933)
at org.robolectric.util.ReflectionHelpers.callInstanceMethod(ReflectionHelpers.java:195)
at org.robolectric.util.ActivityController$1.run(ActivityController.java:122)
at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:304)
at org.robolectric.shadows.CoreShadowsAdapter$2.runPaused(CoreShadowsAdapter.java:45)
at org.robolectric.util.ActivityController.create(ActivityController.java:118)
at org.robolectric.util.ActivityController.create(ActivityController.java:129)
at com.enjoytech.ecar.carpooling.activity.DriverReleaseAcitivityTest.init(DriverReleaseAcitivityTest.java:87)
at com.enjoytech.ecar.carpooling.activity.DriverReleaseAcitivityTest.test(DriverReleaseAcitivityTest.java:79)
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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
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.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Process finished with exit code -1
It couldn't load the .so file.
When I use
try {
System.loadLibrary("libamapv304");
System.loadLibrary("libamapv304ex");
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
}
it cause java.lang.UnsatisfiedLinkError: no libamapv304 in java.library.path
How can I using .so to complete unit test with Roboletric?
I would load native libraries in some controlled way. For simplicity let assume it is in Application:
public class NativeLibApplication extends Application {
...
protected void loadNativeLibraries() {
try {
System.loadLibrary("libamapv304");
System.loadLibrary("libamapv304ex");
} catch (UnsatisfiedLinkError e) {
...
}
}
...
}
Robolectric gives you a possibility to tweak your application under the test. You should create TestNativeLibApplication in the same package under test folder and suppress loading native libraries:
public class TestNativeLibApplication extends NativeLibApplication {
...
#Override
protected void loadNativeLibraries() {
//do nothing
}
...
}
Support libraries that package native libraries
Summary
1. Disable load so in your app code.
2. Porting Dynamic Link Library.
If you use the Linux operating system that is the most simple, just get the x86-64(Depending on your cpu architecture) 's so file, and add the dependency so library(Found in the ndk-bundle, platforms folder).
If you use the masOS operating system, you need to do a little more work. And you should have the native so library source code, and compile it under macOS system:
``` Bash
.o
cc -c -I/System/Library/Frameworks/JavaVM.framework/Headers *.cpp
get xxx.dylib
g++ -dynamiclib -undefined suppress -flat_namespace *.o -o something.dylib
```
Windows is similar.
3. Load so library in your RobolectricApplication.
End, run your test case, well done:
load so test case http://rocko-blog.qiniudn.com/2016-11-27_09-32-15_test_case_success.png
Detail
Sample code: RobolectricSupportNativeLibs

Categories

Resources