Проблемы с модульными тестированием с коратиками котлин и потокомAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Проблемы с модульными тестированием с коратиками котлин и потоком

Сообщение Anonymous »

Я столкнулся с очень странной проблемой при написании модульных тестов для Coroutines и потока.insertScene should return Success тест не удался и сказал мне, что поток не получил значение, но я ясно отправил значение, и последующие методы испытаний, такие как deleteScene should return Success , смогли пройти тест.@RunWith(RobolectricTestRunner::class)
@OptIn(ExperimentalCoroutinesApi::class)
class SceneExecuteRepositoryTest {

@MockK
private lateinit var mockConn: EditorServiceConnection

@MockK
private lateinit var mockEditApi: IEditorApi

@MockK
private lateinit var mockSceneDesc: SceneDesc

private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
private val serviceStateFlow = MutableStateFlow(null)
private val slotActionCallback = slot()
private val sceneExecuteRepository by lazy {
SceneExecuteRepository(mockConn, testScope)
}

@Before
fun setUp() {
MockKAnnotations.init(this)

mockkStatic(XLog::class)
every { XLog.init(any(), any(), any()) } just Runs
every { XLog.tag(any()).d(any()) } just Runs
every { XLog.tag(any()).e(any()) } just Runs

every { mockConn.service } returns serviceStateFlow.filterNotNull()
}

@After
fun tearDown() {
unmockkAll()
}

@Test
fun `insertScene should return Success`() = testScope.runTest {
coEvery {
mockEditApi.insertScene(any(), any(), capture(slotActionCallback))
} answers {
slotActionCallback.captured.onSuccess()
}

serviceStateFlow.value = mockEditApi

val result = sceneExecuteRepository.insertScene(mockSceneDesc, "")

assert(result is SceneActionResult.Success)
coVerify { mockEditApi.insertScene(any(), any(), any()) }
}

@Test
fun `deleteScene should return Success`() = testScope.runTest {
coEvery {
mockEditApi.deleteScene(any(), capture(slotActionCallback))
} answers {
slotActionCallback.captured.onSuccess()
}

serviceStateFlow.value = mockEditApi

val result = sceneExecuteRepository.deleteScene("")

assert(result is SceneActionResult.Success)
coVerify { mockEditApi.deleteScene(any(), any()) }
}

@Test
fun `updateScene should return Success`() = testScope.runTest {
coEvery {
mockEditApi.updateScene(any(), any(), any(), capture(slotActionCallback))
} answers {
slotActionCallback.captured.onSuccess()
}

serviceStateFlow.value = mockEditApi

val result = sceneExecuteRepository.updateScene("", mockSceneDesc, null)

assert(result is SceneActionResult.Success)
coVerify { mockEditApi.updateScene(any(), any(), any(), any()) }
}
}
< /code>
@Singleton
class SceneExecuteRepository @Inject constructor(
private val conn: EditorServiceConnection,
@IoDispatcher private val ioScope: CoroutineScope
) {

companion object {
const val TAG = "SceneExecuteRepository"
}

suspend fun insertScene(
sceneDesc: SceneDesc,
featureId: String? = null
): SceneActionResult {
return executeAction { iEditorApi, callback ->
LogUtil.d(TAG, "insertScene: ${sceneDesc.name}")
iEditorApi.insertScene(sceneDesc, featureId, callback)
}
}

suspend fun deleteScene(sceneId: String): SceneActionResult {
return executeAction { iEditorApi, callback ->
LogUtil.d(TAG, "deleteScene: $sceneId")
iEditorApi.deleteScene(sceneId, callback)
}
}

suspend fun updateScene(
sceneId: String,
sceneDesc: SceneDesc,
featureId: String? = null
): SceneActionResult {
return executeAction { iEditorApi, callback ->
LogUtil.d(TAG, "updateScene: $sceneId")
iEditorApi.updateScene(sceneId, sceneDesc, featureId, callback)
}
}

@OptIn(FlowPreview::class)
private suspend fun executeAction(
action: suspend (IEditorApi, IActionCallback) -> Unit
): SceneActionResult = suspendCancellableCoroutine { coroutine ->
val weakContinuation = WeakReference(coroutine)
val callback = object : IActionCallback.Stub() {
override fun onSuccess() {
weakContinuation.get()?.takeIf { it.isActive }
?.resume(SceneActionResult.Success(Unit))
}

override fun onError(code: Int, desc: String?) {
weakContinuation.get()?.takeIf { it.isActive }
?.resume(SceneActionResult.Error(code, desc ?: ""))
}
}
ioScope.launch {
conn.service
.timeout(3000.milliseconds)
.map {
LogUtil.d(TAG, "$it")
action(it, callback)
}
.catch {
LogUtil.e(TAG, it.toString())
}
.first()
}
}
}


Подробнее здесь: https://stackoverflow.com/questions/796 ... s-and-flow
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»