DateTimeParseException on specific device [duplicate] - android

I am running the following tests to parse time in HH:mm am/pm format all 3 tests pass in Java 8 (1.8.0_282) but 2nd and 3rd test fail in latest Java 11_0_11 version, only the very simple test (first test without am/pm info) passed in Java 11. Also i am running Oracle JDK 11 as well as AdoptOpenJDK 11 with same results.
My Main Requirement
I have incoming JSON payload containing (as strings) before and after times with am/pm information. I need to parse Local Time out of them and then compare the local times against each other to see if one is before the other.
#Test
public void testLocalTime1() { //passed with java8 and java 11
LocalTime localTime = LocalTime.parse("11:15", DateTimeFormatter.ofPattern("HH:mm"));
System.out.println(localTime);
}
#Test
public void testLocalTime2() {//passed with java8 only, failed with java 11
LocalTime test = LocalTime.parse("8:00 am".toUpperCase(),
DateTimeFormatter.ofPattern("h:mm a"));
System.out.println(test);
}
#Test
public void testLocalTime3() {//passed with java8 only, failed with java 11
LocalTime test = LocalTime.parse("11:00 AM",
DateTimeFormatter.ofPattern("HH:mm a"));
System.out.println(test);
}
The error i am getting is
java.time.format.DateTimeParseException: Text '8:00 AM' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.LocalTime.parse(LocalTime.java:463)
at com.company.SampleTest.testLocalTime2_1(SampleTest.java:45)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
The version of Java 11 is latest
java -version
java version "11.0.11" 2021-04-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.11+9-LTS-194)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.11+9-LTS-194, mixed mode)

There are two problems in your code:
You haven't used Locale with DateTimeFormatter which is a Locale-sensitive type. Never use SimpleDateFormat or DateTimeFormatter without a Locale.
You have used H instead of h for 12-hour format. The symbol, H is used for 24-hour format.
Demo:
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("h:m a")
.toFormatter(Locale.ENGLISH);
System.out.println(LocalTime.parse("8:00 am", dtf));
System.out.println(LocalTime.parse("11:00 AM", dtf));
}
}
Output:
08:00
11:00
Learn more about java.time, the modern Date-Time API* from Trail: Date Time.

Related

How to use an android dependency in unit tests?

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’

uses-library com.android.nfc_extras breaks AndroidTest for api 26 and above when testing on a real device

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>

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,

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