如何用Espresso对带用户授权的Sms Retriever进行UI测试?
测试SmsRetriever广播接收与OTP自动填充逻辑(Espresso + Mockito)
没问题,我来帮你梳理如何用Espresso和Mockito完成这个测试——核心是模拟SmsRetriever.SMS_RETRIEVED_ACTION广播的触发流程,验证你的onActivityResult代码能否正确提取OTP并填充到EditText中。下面是分步实现方案:
1. 确认测试依赖
首先确保你的Module级build.gradle里已经添加了必要的测试库:
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'org.mockito:mockito-android:5.6.0' androidTestImplementation 'androidx.test:rules:1.5.0'
2. 初始化测试环境
创建Instrumented测试类,用ActivityTestRule启动承载OTP Fragment的宿主Activity,同时准备好要测试的BroadcastReceiver实例:
@RunWith(AndroidJUnit4::class) class OtpFragmentTest { @get:Rule val activityRule = ActivityTestRule<YourHostActivity>(YourHostActivity::class.java) private lateinit var testBroadcastReceiver: BroadcastReceiver @Before fun setup() { // 获取Fragment实例,拿到你注册的BroadcastReceiver val otpFragment = activityRule.activity.supportFragmentManager .findFragmentById(R.id.your_fragment_container) as MyOtpFragment testBroadcastReceiver = otpFragment.yourBroadcastReceiver // 假设Fragment持有Receiver的引用 } }
3. 模拟广播触发,验证Consent Intent的启动
我们先构造一个成功状态的广播Intent,手动调用Receiver的onReceive方法,验证它是否正确触发了startActivityForResult:
@Test fun testBroadcastReceiverTriggersConsentFlow() { // 1. 构造成功的Status对象 val successStatus = Status(CommonStatusCodes.SUCCESS, "OTP检索成功") // 2. 构造包含Consent Intent的广播Intent val consentIntent = Intent(SmsRetriever.ACTION_SMS_USER_CONSENT) val broadcastIntent = Intent(SmsRetriever.SMS_RETRIEVED_ACTION).apply { putExtra(SmsRetriever.EXTRA_STATUS, successStatus) putExtra(SmsRetriever.EXTRA_CONSENT_INTENT, consentIntent) } // 3. 调用Receiver的onReceive方法 testBroadcastReceiver.onReceive(activityRule.activity, broadcastIntent) // 可选:如果想验证startActivityForResult被调用,可结合Mockito做验证 // 注意:如果用的是registerForActivityResult,需要mock ActivityResultLauncher并验证 }
4. 模拟onActivityResult返回,验证OTP填充
直接模拟onActivityResult的调用,然后用Espresso检查EditText的内容是否正确:
@Test fun testOnActivityResultFillsOtpCorrectly() { val testOtp = "123456" val otpFragment = activityRule.activity.supportFragmentManager .findFragmentById(R.id.your_fragment_container) as MyOtpFragment // 构造模拟的返回Intent,携带测试用的OTP val resultIntent = Intent().apply { putExtra(SmsRetriever.EXTRA_SMS_MESSAGE, testOtp) } // 手动调用Fragment的onActivityResult方法 otpFragment.onActivityResult(SMS_REQUEST_CODE, Activity.RESULT_OK, resultIntent) // 用Espresso验证EditText是否被正确填充 onView(withId(R.id.et_otp)) .check(matches(withText(testOtp))) }
5. 完整流程模拟(广播→同意→填充)
如果你想测试从广播触发到OTP填充的完整流程,可以用Espresso的intending拦截Consent Intent,直接返回成功结果:
@Test fun testFullOtpRetrievalFlow() { val testOtp = "654321" val otpFragment = activityRule.activity.supportFragmentManager .findFragmentById(R.id.your_fragment_container) as MyOtpFragment // 拦截Consent Intent,直接返回携带OTP的成功结果 intending(hasAction(SmsRetriever.ACTION_SMS_USER_CONSENT)) .respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, Intent().apply { putExtra(SmsRetriever.EXTRA_SMS_MESSAGE, testOtp) })) // 触发广播Receiver val successStatus = Status(CommonStatusCodes.SUCCESS, "Success") val consentIntent = Intent(SmsRetriever.ACTION_SMS_USER_CONSENT) val broadcastIntent = Intent(SmsRetriever.SMS_RETRIEVED_ACTION).apply { putExtra(SmsRetriever.EXTRA_STATUS, successStatus) putExtra(SmsRetriever.EXTRA_CONSENT_INTENT, consentIntent) } testBroadcastReceiver.onReceive(activityRule.activity, broadcastIntent) // 等待流程完成,验证OTP填充 onView(withId(R.id.et_otp)) .check(matches(withText(testOtp))) }
小提示
- 如果你的BroadcastReceiver是动态注册的,要确保测试前已经完成注册,或者在测试的
setup方法中手动注册。 - 如果你用的是
registerForActivityResult而非传统的startActivityForResult,需要用Mockito mockActivityResultLauncher,并验证它的launch方法是否被正确调用。 - 确保测试中使用的
SMS_REQUEST_CODE和你业务代码中的常量完全一致。
内容的提问来源于stack exchange,提问作者Jokubas Trinkunas
相关产品推荐
相关产品推荐

