gpt4 book ai didi

android - 如何让 MockWebServer + Retrofit + Coroutines 在同一个调度器中运行

转载 作者:行者123 更新时间:2023-12-05 00:00:32 25 4
gpt4 key购买 nike

我在我的 Android 单元测试中尝试使用 MockWebServer + Retrofit + Coroutines 失败。在调试过程中,我发现 OkHttp 在不同的线程上运行,这就是为什么我的测试总是失败。

这是我设置测试调度程序的规则:

class MainCoroutineRule(
private val scheduler: TestCoroutineScheduler = TestCoroutineScheduler(),
val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(scheduler)
) : TestWatcher() {

val testScope = TestScope(testDispatcher)

override fun starting(description: Description) {
super.starting(description)
Dispatchers.setMain(testDispatcher)
}

override fun finished(description: Description) {
super.finished(description)
Dispatchers.resetMain()
}
}

这是我的 View 模型:

@HiltViewModel
class TestViewModel @Inject constructor(
private val repository: TestRepository,
@MainDispatcher private val dispatcher: CoroutineDispatcher
) : ViewModel() {

val hasData = MutableLiveData(false)

fun fetchSomething() {
viewModelScope.launch(dispatcher) {

when (repository.getSomething()) {
is Success -> {
hasData.value = true
}
else -> {
hasData.value = false
}
}
}
}
}

最后是测试:

class TestViewModelTest : MockServerSuite() {
@get:Rule
val taskExecutorRule = InstantTaskExecutorRule()

@get:Rule
val mainTestRule = MainCoroutineRule()

@Test
fun `my test`() = mainTestRule.testScope.runTest {
// setting up MockWebServer

val viewModel = TestViewModel(
repository = TestRepository(
api = testApi(server),
),
dispatcher = mainTestRule.testDispatcher
)

viewModel.fetchSomething()
assertThat(viewModel.hasData.value).isTrue
}
}

由于 Retrofit 是主安全的,我不知道如何让它在我的 testDispatcher 上运行。我错过了什么吗?

正如 Petrus 提到的,我已经使用了 getOrAwaitValue,它适用于简单的场景。在我们的大多数用例中,我们的请求在收到一些数据后会触发其他请求。通常,我收到 getOrAwaitValue 的中间值,而不是我期望的最终 LiveData。

最佳答案

尝试使用 getOrAwaitValue :)

class TestViewModelTest {
@Test
fun `my test`() = mainTestRule.testScope.runTest {
// setting up MockWebServer

val viewModel = TestViewModel(
repository = TestRepository(
api = testApi(server),
),
dispatcher = mainTestRule.testDispatcher
)

viewModel.fetchSomething()
assertThat(viewModel.hasData.getOrAwaitValue()).isTrue
}
}

@VisibleForTesting(otherwise = VisibleForTesting.NONE)
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)

try {
afterObserve.invoke()

// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
throw TimeoutException("LiveData value was never set.")
}

} finally {
this.removeObserver(observer)
}

@Suppress("UNCHECKED_CAST")
return data as T
}

关于android - 如何让 MockWebServer + Retrofit + Coroutines 在同一个调度器中运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71489875/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com