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
Related
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’
I've suddenly figured out that this declaration:
<uses-library
android:name="com.android.nfc_extras"
android:required="false"/>
inside <application> scope of my AndroidManifest.xml makes instrumentation tests to fail:
java.lang.NoSuchMethodError: No static method allOf(Lorg/hamcrest/Matcher;Lorg/hamcrest/Matcher;)Lorg/hamcrest/Matcher; in class Lorg/hamcrest/core/AllOf; or its super classes (declaration of 'org.hamcrest.core.AllOf' appears in /system/framework/com.android.nfc_extras.jar)
at org.hamcrest.Matchers.allOf(Matchers.java:33)
at android.support.test.espresso.Espresso.<clinit>(Espresso.java:187)
at android.support.test.espresso.Espresso.onView(Espresso.java:75)
at com.example.abusik.espressotest.InstrumentedTest.changeText_sameActivity(InstrumentedTest.kt:34)
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)
What I came up with for now:
Created a demo repository for you to be able to reproduce the problem quickly;
Only a real devices with API >= 26 are affected (e.g. Samsung SM-G935F, Huawei P20 lite);
Test passes on emulators with any API I have tried;
Test passes on real devices with API < 26;
Looks like missing class (and all his static methods) are included into AndroidTest apk, but at runtime Android tries to get this class from com.android.nfc_extras.jar???;
This behaviour may depend on NFC-feature of your phone;
It doesn't looks like MultiDex or obfuscation problem for me - the demo repository is not obfuscated and single-dex.
I would like to know if anybody faced this problem, why is this happening and how can I keep my AndroidTests working and still use this library?
My InstrumentedTest.kt file:
package com.example.abusik.espressotest
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.*
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText
import android.support.test.filters.LargeTest
import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
#RunWith(AndroidJUnit4::class)
#LargeTest
class InstrumentedTest {
private lateinit var stringToBetyped: String
#get:Rule
var activityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)
#Before
fun initValidString() {
// Specify a valid string.
stringToBetyped = "Espresso"
}
#Test
fun changeText_sameActivity() {
// Type text and then press the button.
onView(withId(R.id.et)) //EXCEPTION THROWN HERE
.perform(typeText(stringToBetyped), closeSoftKeyboard())
onView(withId(R.id.btn)).perform(click())
// Check that the text was changed.
onView(withId(R.id.et))
.check(matches(withText(stringToBetyped)))
}
}
Test log:
Testing started at 0:09 ...
12/17 00:09:32: Launching InstrumentedTest
$ adb push /Users/a.busik/EspressoTest/app/build/outputs/apk/debug/app-debug.apk /data/local/tmp/com.example.abusik.espressotest
$ adb shell pm install -t -r "/data/local/tmp/com.example.abusik.espressotest"
Success
APK installed in 3 s 235 ms
$ adb push /Users/a.busik/EspressoTest/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk /data/local/tmp/com.example.abusik.espressotest.test
$ adb shell pm install -t -r "/data/local/tmp/com.example.abusik.espressotest.test"
Success
APK installed in 2 s 684 ms
Running tests
$ adb shell am instrument -w -r -e debug false -e class 'com.example.abusik.espressotest.InstrumentedTest' com.example.abusik.espressotest.test/android.support.test.runner.AndroidJUnitRunner
Client not ready yet..
Started running tests
java.lang.NoSuchMethodError: No static method allOf(Lorg/hamcrest/Matcher;Lorg/hamcrest/Matcher;)Lorg/hamcrest/Matcher; in class Lorg/hamcrest/core/AllOf; or its super classes (declaration of 'org.hamcrest.core.AllOf' appears in /system/framework/com.android.nfc_extras.jar)
at org.hamcrest.Matchers.allOf(Matchers.java:33)
at android.support.test.espresso.Espresso.<clinit>(Espresso.java:187)
at android.support.test.espresso.Espresso.onView(Espresso.java:75)
at com.example.abusik.espressotest.InstrumentedTest.changeText_sameActivity(InstrumentedTest.kt:34)
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:527)
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:68)
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.-wrap0(Unknown Source:0)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at android.support.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:101)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:126)
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.-wrap0(Unknown Source:0)
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:56)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2106)
Tests ran to completion.
I was able to find an nfc_extras.jar and it doesn't seem to contain any reference for org.hamcrest.*
unable to reproduce on a physical MotoX4 running Android 8.0.0.
a) com.android.nfc_extras.jar might have another version of org.hamcrest.Matcher than the test application - which could theoretically be excluded, when loading it from the libs directory. that the emulator does not care might come from, that there neither is BT nor NFC available.
the main/Manifest.xml also lacks the NFC permission; adding it removes the complaint:
<uses-permission android:name="android.permission.NFC" />
b) one could even get rid of the nfc_extras.jar altogether with an androidTest/Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.abusik.espressotest">
<application>
<uses-library
android:name="com.android.nfc_extras"
android:required="false"
tools:node="remove"/>
</application>
</manifest>
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"
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,
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/