[英]Android UI tests with Espresso + MockK crash with SIGSEGV on emulators, fine on physical devices
我刚刚开始使用MockK在基于 MVP 的应用程序中模拟所有存储库/服务逻辑以进行 UI 测试。
我有一些运行登录活动的 UI 测试,其中 Espresso 输入登录名和密码并使用 MockK 我可以伪造登录失败与否的各种情况。
所有服务和存储库都是标准的 Kotlin object,所以我使用mockkobject
和every/coEvery
来覆盖和处理登录请求和任务。
在我的物理设备上,测试完全没有问题,但是当我尝试在运行 Android P+ 并带有推荐图像的模拟器上运行它们时,它们会在随机时间不断崩溃。 在极少数情况下,他们可以存活足够长的时间来工作。
查看日志,我得到了各种 SIGSEGV:
A/libc:致命信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR),tid 10425 (e.android.debug) 中的故障地址 0x0,pid 10425 (e.androiddebug)。
A/libc:致命信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR),tid 10968 (HeapTaskDaemon) 中的故障地址 0xc,pid 10957 (e.android.debug)
A/libc:致命信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR),tid 15050 (firebase-instal) 中的故障地址 0x0,pid 14972 (e.android.debug)
A/libc:致命信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR),tid 8902(测量工作)中的故障地址 0xd,pid 8858(e.android.debug)
A/libc:致命信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR),tid 22004 (Binder:21832_5) 中的故障地址 0x0,pid 21832 (e.android.debug)
但更深入地研究日志,我相信我找到了罪魁祸首:
InputDispatcher: 通道 '9fa7335 my.company.com.android.debug/my.company.com.ui.login.Login 将被销毁(无法恢复)
寻找解决方案,这似乎是由于 memory 泄漏而发生的?
无论如何,我确保在@Before
方法中启动被测活动,在该方法中,当我清除此类模拟并在@After
方法中进行验证时,所有模拟都会发生。
显然,我相信测试确实可以正常工作,但 Espresso 或所有发生的 mocking 肯定有问题......
进一步查看之前的日志,这可能是存在 memory 泄漏的原因:
ActivityThread: Service com.google.android.gms.autofill.service.AutofillService has leaked IntentReceiver com.google.android.gms.autofill.smsretriever.TracingSmsBroadcastReceiver@ce00658 that was originally registered here. 您是否错过了对 unregisterReceiver() 的调用? android.app.IntentReceiverLeaked: Service com.google.android.gms.autofill.service.AutofillService has leaked IntentReceiver com.google.android.gms.autofill.smsretriever.TracingSmsBroadcastReceiver@ce00658 that was originally registered here. 您是否错过了对 unregisterReceiver() 的调用?
我在我的模拟器上禁用了 AutoFillService(在相关设置部分中设置为 none)。 这似乎在一开始提高了我的测试成功率,但在几次运行后它们一直在崩溃。 不过,现在日志不再显示此泄漏。
显然,这个问题可能与 MockK 有关,因为我能够检索更多日志:
2020-07-24 11:57:15.955 15767-15780/com.my.company.android.debug A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 15780 (HeapTaskDaemon), pid 15767 (e.android.debug)
2020-07-24 11:57:15.997 15962-15962/? E/crash_dump32: failed to detach from thread 15773: No such process
2020-07-24 11:57:15.997 15962-15962/? E/crash_dump32: failed to detach from thread 15778: No such process
2020-07-24 11:57:15.997 15962-15962/? E/crash_dump32: failed to detach from thread 15779: No such process
2020-07-24 11:57:15.997 15962-15962/? E/crash_dump32: failed to detach from thread 15780: No such process
// 20 more times of exact same line //
2020-07-24 11:57:16.007 15962-15962/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2020-07-24 11:57:16.007 15962-15962/? A/DEBUG: Build fingerprint: 'google/sdk_gphone_x86/generic_x86:10/QSR1.190920.001/5891938:user/release-keys'
2020-07-24 11:57:16.007 15962-15962/? A/DEBUG: Revision: '0'
2020-07-24 11:57:16.007 15962-15962/? A/DEBUG: ABI: 'x86'
2020-07-24 11:57:16.008 15962-15962/? A/DEBUG: Timestamp: 2020-07-24 09:57:16+0000
2020-07-24 11:57:16.008 15962-15962/? A/DEBUG: pid: 15767, tid: 15780, name: HeapTaskDaemon >>> com.my.company.android.debug <<<
2020-07-24 11:57:16.008 15962-15962/? A/DEBUG: uid: 10136
2020-07-24 11:57:16.008 15962-15962/? A/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
2020-07-24 11:57:16.008 15962-15962/? A/DEBUG: Cause: null pointer dereference
2020-07-24 11:57:16.008 15962-15962/? A/DEBUG: eax 00000000 ebx ef8a6c34 ecx 00000000 edx f310b604
2020-07-24 11:57:16.008 15962-15962/? A/DEBUG: edi f3200380 esi 00000000
2020-07-24 11:57:16.008 15962-15962/? A/DEBUG: ebp e659d9a8 esp e659d940 eip ef7d89f4
2020-07-24 11:57:16.027 2044-2135/? E/InputDispatcher: channel '342ebda com.my.company.android.debug/com.my.compan.android.ui.error.LoginActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
经过进一步调查,在 Android 测试 Github 存储库中有一个存在 1 年的问题(但问题现已关闭): https/ android-test/android-test/android-test/github.com
Mockk 的相关问题已在此处打开: https://github.com/mockk/mockk/issues/466
我正在探索 go 的替代方案,回到Mockito
,它具有更多的历史和更积极的发展。 花了一些时间,但我没有遇到重大问题将我的 UI 测试迁移到 Mockito。
结果:嗯,起初崩溃完全消失了。 我可以毫不费力地进行 10、20、30 次测试。 至少在手机上。
然而,在 Android 电视上(仍然有模拟器),崩溃很快再次出现。 然后在移动设备上也是如此,但来自InputDispatcher
的可怕消息的频率要低得多。
While setting up the migration to Mockito, I have noticed that Mockk shares the same restrictions & dependencies with Mockito when mocking on Android Test Instrumentation. 我面临同样的问题和同样的困难。
所以这让我相信他们都不是罪魁祸首,但它很可能是 Android Instrumentation API。
我还注意到手动重启模拟器大大改善了这种情况。
这是在我的堆栈跟踪中:
W Unexpected CPU variant for X86 using defaults: x86
ActivityThread W Package uses different ABI(s) than its instrumentation:
切换到 64 位模拟器解决了这个问题。
我的仪器测试套件也遇到了这个问题,并且怀疑 MockK (至少部分)有问题。
这远非真正的解决方案,但我注意到使用 Android Test Orchestrator 运行我的测试大大降低了由于测试进程崩溃(由上述段错误引起)导致的随机失败的机会。 (如果您使用 Firebase 测试实验室仿真器运行测试,这可能特别有用。)使用 Orchestrator 的另一个好处是,它在挖掘日志(在 Firebase 测试实验室)以找到根本错误方面做得非常好。在 Orchestrator 进程中确实失败。
我不确定这对每个人都适用,但如果确实如此,它可能表明 MockK(如果它确实是这个问题的根源)没有完全清理并且正在泄漏到其他测试中。
我有完全相同的情况,我的测试在模拟器上随机崩溃, Process crashed
错误说检查 Logcat。 Logcat 上存在SIGSEGV
错误,但并非总是如此。
在我的情况下,它是com.linkedin.dexmaker:dexmaker-mockito-inline
导致随机崩溃。 我不得不将它添加到在我根本不需要的仪器测试中模拟 Kotlin 数据 class 。 所以删除这个依赖解决了我的问题。
我建议调查一下您的测试在什么时候开始崩溃,这样会更容易深入了解它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.