Unit tests involving MockWebServer fails with Auth0's Android library version 2

  • Which SDK this is regarding: Android SDK
  • SDK Version: version 2.0.0
  • Platform Version: Android 11

Hello everyone, we just upgraded our Auth0 Android lib to version 2 from version 1.30, and some of our unit tests that use OkHttp's MockWebServer broke, here are the details:

  1. The first test fails with a java.lang.ExceptionInInitializerError which in turn is caused by java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked.
  2. Next three tests fail with java.lang.NoClassDefFoundError: Could not initialize class com.auth0.android.request.internal.DefaultThreadSwitcher
  3. The rest of the tests are stuck until cancelled.

For context, we use RxJava3 and Android Jetpack libs such as LiveData in our code base, and Retrofit for REST API. For our unit tests we use mockk and JUnit5.

Here is a code snippet on how our test looks like:

class AuthManagerTest {

    ...
    private lateinit var authManager: AuthManager
    private lateinit var config: Auth0Config
    private lateinit var server: MockWebServer

    @MockK
    private lateinit var context: Context

    @MockK
    private lateinit var credentialsManager: SecureCredentialsManager

    ...

    ...

    @BeforeEach
    fun setup() {
        MockKAnnotations.init(this)
        every { context.getSharedPreferences(any(), any()) } returns mockk()
        every { credentialsManager.authToken } returns null
        every { credentialsManager.userId } returns null
        every { credentialsManager.refreshToken } returns null
        every { credentialsManager.saveCredentials(any()) } just Runs

        ...

        mockkObject(Credentials.Companion)
        every { Credentials.fromAuth0Creds(any(), any()) } returns mockk()
        server = MockWebServer().apply {
            // we didn't use useHttps before but with the new version of Auth0 it seems https is mandatory
            useHttps(testSslSocketFactory(), false)
            start()
        }
...
}

Here are the first tests in the aforementioned class:

    @Test
    fun `sendEmailCode returns EmailSent when response is successful`() {
        server.enqueue(mockResponse(200, email_success_response))
        val emailResult = authManager.sendEmailCode("me@example.org").blockingGet()
                as EmailResult.EmailSent
        assertEquals("me@example.org", emailResult.email)
        assertNoToken()
    }

    @Test
    fun `sendEmailCode returns InvalidEmail when response gives invalid email error`() {
        server.enqueue(mockResponse(400, email_invalid_response))
        val result = authManager.sendEmailCode("me.org").blockingGet()
                as EmailResult.InvalidEmail
        assertEquals("bad.email", result.code)
        assertEquals("blah blah", result.description)
        assertNoToken()
    }

    @Test
    fun `sendEmailCode returns NetworkError when server is down`() {
        server.shutdown()
        val result = authManager.sendEmailCode("me@example.org").blockingGet()
        assertTrue(result is EmailResult.NetworkError)
        assertNoToken()
    }

    @Test
    fun `sendEmailCode returns UnknownError when response gives unknown error`() {
        server.enqueue(mockResponse(400, email_unknown_response))
        val result = authManager.sendEmailCode("me@example.org").blockingGet()
                as EmailResult.UnknownError
        assertEquals("bad.send", result.code)
        assertEquals("error in send - No enum match for: links", result.description)
        assertNoToken()
    }

    @Test
    fun `login with code returns Success when response is successful`() {
        server.enqueue(mockResponse(200, email_code_success))

        val credSlot = slot<Auth0Credentials>()
        val regionSlot = slot<String>()
        every {
            credentialsManager.saveCredentials(
                Credentials.fromAuth0Creds(capture(credSlot), capture(regionSlot))
            )
        } just Runs

        val result = authManager.login("email", "1234").blockingGet()
                as AuthResult.Success
        assertNotNull(result)
        verify(exactly = 1) { credentialsManager.saveCredentials(any()) }
        val cred = credSlot.captured
        assertEquals("jwt.t0k3n", cred.idToken)
        assertEquals("4cc3ssToken", cred.accessToken)
        assertEquals("reeefreshToken", cred.refreshToken)
        assertEquals("nz", regionSlot.captured)
    }


I tried adding @ExtendWith(InstantExecutorExtension::class, RxImmediateScheduler::class) in the class declaration like this:

@ExtendWith(InstantExecutorExtension::class, RxImmediateScheduler::class)
class AuthManagerTest {

But afterwards, all tests return with “Test ignored” in the logs:

Test ignored.

java.lang.InstantiationException
    at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:513)
    at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:488)
    at org.junit.jupiter.engine.extension.MutableExtensionRegistry.registerExtension(MutableExtensionRegistry.java:176)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.jupiter.engine.extension.MutableExtensionRegistry.createRegistryFrom(MutableExtensionRegistry.java:117)
    at org.junit.jupiter.engine.descriptor.ExtensionUtils.populateNewExtensionRegistryFromExtendWithAnnotation(ExtensionUtils.java:77)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.prepare(ClassBasedTestDescriptor.java:143)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.prepare(ClassBasedTestDescriptor.java:78)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:111)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:111)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

Also, I’ve posted this in stackoverflow but got no answer. If crossposting is not allowed then just remove this post. I just figured that this forum might be a better venue to ask questions regarding Auth0 library. Thanks.