Open
Description
Environment
- Android Studio version:
- Firebase Component: Firebase Performance
- Component version: >= 20.3.1
- Firebase performance plugin version: 1.4.2
- Mockk library version : 1.13.7 (but the same can be reproduced without mockk)
- Robolectric version: 4.10.3
Problem
Unable to mockk okhttp Call.Factory in a Robolectric test.
Steps to reproduce:
- Add firebase performance to the project
- Have a class
Requester
that takes Call.Factory as an constructor parameter and a methoddoRequest
that makes new okhttp3 call and executes it - In the
Requester
class use the call factory to create a call and execute it - Make a Robolectric test that mocks Call.Factory using Mockk library and pass the factory to the new instance of the
Requester
class - Invoke the
doRequest
method - See the exception
Relevant Code:
class Requester(private val callFactory: Call.Factory) {
fun doRequest() {
callFactory.newCall(Request.Builder().url("https://google.com").build())
.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) {}
})
}
}
@RunWith(RobolectricTestRunner::class)
class ExampleUnitTest {
@Test
fun exampleUntTest() {
val call: Call = mockk(relaxed = true)
val callFactory: Call.Factory = mockk {
every { newCall(any()) } returns call
}
Requester(callFactory).doRequest()
}
}
Running the test results with the following exception
java.lang.ExceptionInInitializerError
at com.google.firebase.perf.config.ConfigResolver.<init>(ConfigResolver.java:78)
at com.google.firebase.perf.config.ConfigResolver.getInstance(ConfigResolver.java:86)
at com.google.firebase.perf.application.AppStateMonitor.<init>(AppStateMonitor.java:98)
at com.google.firebase.perf.application.AppStateMonitor.getInstance(AppStateMonitor.java:87)
at com.google.firebase.perf.metrics.NetworkRequestMetricBuilder.<init>(NetworkRequestMetricBuilder.java:92)
at com.google.firebase.perf.metrics.NetworkRequestMetricBuilder.builder(NetworkRequestMetricBuilder.java:84)
at com.google.firebase.perf.network.InstrumentOkHttpEnqueueCallback.<init>(InstrumentOkHttpEnqueueCallback.java:42)
at com.google.firebase.perf.network.FirebasePerfOkHttpClient.enqueue(FirebasePerfOkHttpClient.java:73)
at com.threekk.firebaseperf.issue.Requester.doRequest(Requester.kt:13)
at com.threekk.firebaseperf.issue.ExampleUnitTest.exampleUntTest(ExampleUnitTest.kt:21)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
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.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:589)
at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:290)
at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:99)
at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process null. Make sure to call FirebaseApp.initializeApp(Context) first.
at com.google.firebase.FirebaseApp.getInstance(FirebaseApp.java:179)
at com.google.firebase.perf.config.RemoteConfigManager.getInitialStartupMillis(RemoteConfigManager.java:91)
at com.google.firebase.perf.config.RemoteConfigManager.<init>(RemoteConfigManager.java:85)
at com.google.firebase.perf.config.RemoteConfigManager.<clinit>(RemoteConfigManager.java:52)
... 26 more
Comments
This doesn't happen when the call.factory is used in tests directly and not in the Requester class. So I believe the instrumentation is done on the argument passed to the Requester class and that breaks things.
No need to use Mockk to create Call.Factory
, the same effect is with any dummy implementation done for the testing purposes.
Attachments
A toy project that is reproducing the issue
firebase-perf-issue.zip