Skip to content

Unable to mockk okhttp3.Call.Factory in unit test when firebase-perf is enabled #5260

Open
@mkubiczek

Description

@mkubiczek

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 method doRequest 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions