验证暂停功能在模拟一段时间后尚未返回值

发布于 2025-02-08 12:50:01 字数 1341 浏览 1 评论 0原文

我试图验证悬挂功能在一定的测试中根本不会返回任何内容。

考虑以下情况:

val completionSignal = Channel<Unit>(capacity = 1, onBufferOverflow = BufferOverflow.DROP_LATEST)

suspend fun waitForCompletionSignal(): String {
  completionSignal.receive()
  return "Completion signal received"
}

我想通过2个单元测试测试此代码,一个验证它在我提供一个值的完成时返回字符串(这很容易)。 当我不给任何东西时,它验证它不会返回任何东西的一个。这是很难的,因为我应该等多长时间?如果我的代码更改并突然返回字符串,我可以确保测试失败吗?

我得到了以下方法,但我缺少一些文章:

@Test
fun `waitForCompletionSignal when completionSignal is provided assert result`() = runTest {
  // Start waiting for result
  val result = async { waitForCompletionSignal() }
  // Provide completion signal
  completionSignal.trySend(Unit)

  // Await result and verify its correct
  assertThat(result.await() == "Completion signal received")
}

@Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
  // Start waiting for result
  val result = async { waitForCompletionSignal() }

  // TODO?? some validation that succeeds if the test is just like this, but fails when i do the following:
  completionSignal.trySend(Unit)
  // A regular await would wait indefinately, and checking if the deferred result is completed does not work very well as well.
}

我希望这个问题很明确,谢谢。

I am trying to validate that a suspend function does not return anything at all in a certain test.

Consider the following situation:

val completionSignal = Channel<Unit>(capacity = 1, onBufferOverflow = BufferOverflow.DROP_LATEST)

suspend fun waitForCompletionSignal(): String {
  completionSignal.receive()
  return "Completion signal received"
}

I want to test this code with 2 unit tests, one that validates it returns the string when I provide the CompletionSignal with a value (thats the easy one).
And one that validates that it does not return anything when i don't give it anything. This is the hard one, since how long should I wait? And can i be sure the test fails if my code changes and suddenly the string is returned?

I got the following approach but I am missing some pieces:

@Test
fun `waitForCompletionSignal when completionSignal is provided assert result`() = runTest {
  // Start waiting for result
  val result = async { waitForCompletionSignal() }
  // Provide completion signal
  completionSignal.trySend(Unit)

  // Await result and verify its correct
  assertThat(result.await() == "Completion signal received")
}

@Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
  // Start waiting for result
  val result = async { waitForCompletionSignal() }

  // TODO?? some validation that succeeds if the test is just like this, but fails when i do the following:
  completionSignal.trySend(Unit)
  // A regular await would wait indefinately, and checking if the deferred result is completed does not work very well as well.
}

I hope the question is clear, thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

红颜悴 2025-02-15 12:50:01

我在延期类型上制作了扩展功能,以便能够等待最大的时间,然后它将返回null。在我的特殊情况下,延迟时间为0(因此,任何延迟)就足够了,但是我可以想象,在某些情况下,它有助于延迟最少的时间。


@ExperimentalCoroutinesApi
suspend inline fun <reified T> Deferred<T>.awaitOrNull(
    time: Long = 0,
    crossinline actBlock: () -> Unit = { }
): T? = coroutineScope {
    actBlock()

    val timeoutJob = async<T?> {
        delay(time)
        null
    }

    return@coroutineScope select<T?> {
        [email protected] {
            timeoutJob.cancel()
            it
        }
        timeoutJob.onAwait {
            [email protected]()
            it
        }
    }
}

使用此方法,我可以按照预期编写以下未能失败 /成功的测试:

// Succeeds
@Test
fun `waitForCompletionSignal when completionSignal is provided assert result`() = runTest {
  val result = async { 
    waitForCompletionSignal()
  }.awaitOrNull {
    completionSignal.trySend(Unit)
  }

  assertThat(result == "Completion signal received")
}

// Succeeds
@Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
  val result = async { 
    waitForCompletionSignal()
  }.awaitOrNull()

  assertThat(result == null)
}

// Fails (to prove that it works)
@Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
  val result = async { 
    waitForCompletionSignal()
  }.awaitOrNull {
    completionSignal.trySend(Unit) // This (obviously) causes the test to fail, as I wanted.
  }

  assertThat(result == null)
}

I made an extension function on the deferred type to be able to wait for a max amount of time and after that it will return null. In my particular situation a delay time of 0 (so no delay whatsoever) is enough, but I can imagine that in some situations its useful to delay for a minimum amount of time.


@ExperimentalCoroutinesApi
suspend inline fun <reified T> Deferred<T>.awaitOrNull(
    time: Long = 0,
    crossinline actBlock: () -> Unit = { }
): T? = coroutineScope {
    actBlock()

    val timeoutJob = async<T?> {
        delay(time)
        null
    }

    return@coroutineScope select<T?> {
        [email protected] {
            timeoutJob.cancel()
            it
        }
        timeoutJob.onAwait {
            [email protected]()
            it
        }
    }
}

Using this method i can write the following tests that fail / succeed as expected:

// Succeeds
@Test
fun `waitForCompletionSignal when completionSignal is provided assert result`() = runTest {
  val result = async { 
    waitForCompletionSignal()
  }.awaitOrNull {
    completionSignal.trySend(Unit)
  }

  assertThat(result == "Completion signal received")
}

// Succeeds
@Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
  val result = async { 
    waitForCompletionSignal()
  }.awaitOrNull()

  assertThat(result == null)
}

// Fails (to prove that it works)
@Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
  val result = async { 
    waitForCompletionSignal()
  }.awaitOrNull {
    completionSignal.trySend(Unit) // This (obviously) causes the test to fail, as I wanted.
  }

  assertThat(result == null)
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文