涉及 MockWebServer 的单元测试因 Auth0 的 Android 库版本 2 而失败

Posted

技术标签:

【中文标题】涉及 MockWebServer 的单元测试因 Auth0 的 Android 库版本 2 而失败【英文标题】:Unit tests involving MockWebServer fails with Auth0's Android library version 2 【发布时间】:2021-05-19 22:09:54 【问题描述】:

我们将 Auth0 android 库从 1.30 升级到 2.0,我们的一些使用 OkHttp 的 MockWebServer 的单元测试坏了。

    第一个测试失败,java.lang.ExceptionInInitializerError 又是由java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. 引起的 接下来的三个测试失败,java.lang.NoClassDefFoundError: Could not initialize class com.auth0.android.request.internal.DefaultThreadSwitcher 其余的测试在取消之前一直卡住。

就上下文而言,我们在代码库中使用 RxJava3 和 Android Jetpack 库,例如 LiveData,以及用于 REST API 的 Retrofit。

我尝试添加 @ExtendWith(InstantExecutorExtension::class, RxImmediateScheduler::class) 在类声明中是这样的:

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

但之后,所有测试都会在日志中返回“测试被忽略”:

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)

这是一段关于我们如何初始化测试类的代码sn-p:

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()
        
...

这是第一个失败的测试:

    @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()
    

【问题讨论】:

【参考方案1】:

已经用 Auth0 android lib 的 2.3.0 版本修复——请参阅 README 以了解如何解决此问题 here

【讨论】:

以上是关于涉及 MockWebServer 的单元测试因 Auth0 的 Android 库版本 2 而失败的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 MockWebServer 验证 POST 正文的内容?

测试时如何从 MockWebServer 中提取参数?

未解决的参考:mockwebserver

text 安卓中使用MockWebServer测试API

使用 Retrofit 和 MockWebServer 模拟无网络

使用 MockWebServer 模拟嵌套的改造 api 调用