如何制作 MockWebServer +改造 +协程在同一个调度程序中运行
我在 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()
}
}
这是我的 ViewModel:
@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。
I'm unsuccessfully trying to use MockWebServer + Retrofit + Coroutines on my Android unit tests. During debugging, I found out that OkHttp is running on a different thread, which is why my test always fails.
This is my rule to set the test dispatcher:
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()
}
}
this is my ViewModel:
@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
}
}
}
}
}
And finally the test:
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
}
}
Since Retrofit is main-safe, I have no idea how to make it run on my testDispatcher. Am I missing something?
As Petrus mentioned, I already use getOrAwaitValue
, which works for simple scenarios.
Our requests fire other requests after receiving some data in most of our use cases.
Usually, I receive intermediate values of getOrAwaitValue and not the final LiveData I was expecting.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
尝试使用 getOrAwaitValue :)
Try to use
getOrAwaitValue
:)