【问题标题】:Coroutines Test exception is not handled with neither TestCoroutineDispatcher nor TestCoroutineScope协程测试异常未使用 TestCoroutineDispatcher 和 TestCoroutineScope 处理
【发布时间】:2020-05-11 13:13:44
【问题描述】:

使用这个manual 来测试协程。编写一个预期会引发异常崩溃而不是通过测试的测试。我想知道我做错了什么。

    private val testDispatcher = TestCoroutineDispatcher()

    @Before
    fun setup() {
        // provide the scope explicitly, in this example using a constructor parameter
        Dispatchers.setMain(testDispatcher)
    }

    @After
    fun cleanUp() {
        Dispatchers.resetMain()
        testDispatcher.cleanupTestCoroutines()
    }

    @Test(expected = RuntimeException::class)
    fun testSomeFunctionWithException() = testDispatcher.runBlockingTest {
        someFunctionWithException()
    }


    private fun someFunctionWithException() {
        MainScope().launch {
            throw RuntimeException("Failed via TEST exception")
        }
    }

上面和下面的测试方法

    private val testScope = TestCoroutineScope()
    private lateinit var subject: Subject

    @Before
    fun setup() {
        // provide the scope explicitly, in this example using a constructor parameter
        subject = Subject(testScope)
    }

    @After
    fun cleanUp() {
        testScope.cleanupTestCoroutines()
    }


    @Test(expected = RuntimeException::class)
    fun testFooWithException() = testScope.runBlockingTest {
        subject.fooWithException()
    }

    class Subject(private val scope: CoroutineScope) {


        fun fooWithException() {
            scope.launch {
                println("fooWithException() thread: ${Thread.currentThread().name}")
                throw RuntimeException("Failed via TEST exception")
            }
        }
    }

即使它们都崩溃了

注意:最好在不复杂的情况下提供 TestCoroutineScope 代码,因为它还会将异常提升为测试失败。

  1. 为什么它们都崩溃了?
  2. 为什么有作用域的那个不失败反而崩溃了?

【问题讨论】:

    标签: unit-testing kotlin kotlin-coroutines


    【解决方案1】:

    TestCoroutineScope 使用TestCoroutineExceptionHandler 将处理在协程中抛出的所有异常,将它们收集到uncaughtExceptions 列表中,尽管第一个异常将在cleanUp 或更具体地在调用cleanupTestCoroutines() 时重新抛出,所以你必须对该异常做一些事情来防止测试失败。

    @After
    fun cleanUp() {
        try {
            testScope.cleanupTestCoroutines()
        } catch (e: Exception) {
            //Do something here
        }
    }
    

    在测试期间,您可以检查uncaughtExceptions 列表以做出断言:

    @Test(expected = RuntimeException::class)
    fun testFooWithException() = testScope.runBlockingTest {
        subject.fooWithException()
        assertEquals(1, uncaughtExceptions.size)
        assertEquals(uncaughtExceptions[0].message, "Failed via TEST exception")
    }
    

    【讨论】:

    • testScope.cleanupTestCoroutines() 放入try-catch 块内工作。
    • TestDispatcher 测试仍然崩溃,即使我将它的 cleanupTestCoroutines 放在 try-catch 中
    【解决方案2】:

    我没有可以轻松测试以下内容的环境,但请尝试将 runBlocking 块放入测试函数的主体中。例如:

    @Test
    fun myTest() {
        runBlocking {
            // Do your test stuff here
        }
    }
    

    我发现我在测试用例中遇到了问题,我之前使用了fun myTest() = runBlocking{ 声明。似乎测试运行程序无法在没有某种断言的情况下检测到测试的执行,并且没有返回。类似的东西。

    无论如何,希望对您有所帮助。

    【讨论】:

    • 感谢您的回答,它有效,但这里的问题是使用 TestCoroutineScope 或 TestCoroutineDispatcher。我赞成它,但格伦的回答解决了 TestCoroutineScope 的问题
    猜你喜欢
    • 1970-01-01
    • 2019-03-22
    • 2019-10-17
    • 2011-12-02
    • 2022-08-10
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多