当涉及到测试片段时,文档是相当好的,但是没有关于如何测试使用ActivityResult的Activity的信息。
我们应该如何在活动测试中覆盖activityResultRegistry
?
我没有准确地阅读文档。
注意:任何允许你在测试中注入单独的
ActivityResultRegistry
的机制都足以测试你的活动结果调用。
强调这个词,注入。
我在我的项目中使用Koin,所以我决定使用Scopes api来创建ActivityResultRegistry
的活动范围实例,我将其注入我的registerForActivityResult
-调用。
val activityScopeModule = module {
scope<MyActivity> {
scoped { get<ComponentActivity>().activityResultRegistry }
}
}
class MyActivity: AppCompatActivity() {
private val requestPermLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
get<ActivityResultRegistry>() // Koin injection
) { granted ->
// handle
}
}
通过使用DI,在测试中注入ActivityResultRegistry
的自定义测试实例变得非常容易。
关于该主题的有用博客文章(使用Hilt实现相同的任务):https://blog.stylingandroid.com/activity-result-contract-outside-the-activity/
关于Koin Scopes API的博文:https://proandroiddev.com/understanding-android-scopes-with-koin-cfe6b60ca579
在一个单独的文件中编写你的契约,这样你就可以很容易地测试契约,并在运行时提供你自己的activityresultreregistry来获得预期的结果。从活动中调用真正的合约进行测试是不好的做法。设计契约的核心目的之一是将活动代码与onactiityresults
解耦。class ImageContract(registry: ActivityResultRegistry) {
private val contractUriResult : MutableLiveData<Uri> = MutableLiveData(null)
private val getPermission = registry.register(REGISTRY_KEY, ActivityResultContracts.GetContent()) { uri ->
contractUriResult.value = uri
}
fun getImageFromGallery(): LiveData<Uri> {
getPermission.launch("image/*")
return contractUriResult
}
companion object {
private const val REGISTRY_KEY = "Image Picker"
}
}
在你的活动
ImageContractHandler(activityResultRegistry).getImageFromGallery().observe(this, {
it?.let { u ->
backgroundImageView.setImageURI(u)
}
})
测试
@Test
fun activityResultTest() {
// Create an expected result URI
val testUrl = "file//dummy_file.test"
val expectedResult = Uri.parse(testUrl)
// Create the test ActivityResultRegistry
val testRegistry = object : ActivityResultRegistry() {
override fun <I, O> onLaunch(
requestCode: Int,
contract: ActivityResultContract<I, O>,
input: I,
options: ActivityOptionsCompat?
) {
dispatchResult(requestCode, expectedResult)
}
}
val uri = ImageContractHandler(testRegistry).getImageFromGallery().getOrAwaitValue()
assert(uri == expectedResult)
}
在测试中监听同一线程上的LiveData一个著名的LiveData测试扩展
fun <T> LiveData<T>.getOrAwaitValue(
time: Long = 2,
timeUnit: TimeUnit = TimeUnit.SECONDS,
afterObserve: () -> Unit = {}
): T {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
this@getOrAwaitValue.removeObserver(this)
}
}
this.observeForever(observer)
afterObserve.invoke()
// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
this.removeObserver(observer)
throw TimeoutException("LiveData value was never set.")
}
@Suppress("UNCHECKED_CAST")
return data as T
}