Как установить тайм-аут для пакета Async в Scalatest?
Рассмотрим следующий пример модульного теста:
class MySpec extends AsyncFlatSpec {
"this" should "fail after some timeout" in {
val resultFuture: Future[_] = Promise().future
for (result <- resultFuture) yield {
assert(result == ???) // some assertions
assert(result == ???) // some assertions
assert(result == ???) // some assertions
}
}
}
Проблема
Если
resultFuture
никогда не завершает набор тестов, также никогда не завершается. Насколько я понимаю, это связано с тем, как
SerialExecutionContext
реализуется.
Вопрос
Есть ли какой-нибудь «хороший» способ установить тайм-аут для такого рода тестов, чтобы, если будущее не завершено, тест просто провалился, вместо того, чтобы блокировать весь набор тестов на вечность?
ОБНОВЛЕНИЕ и уточнение
В то время как решения https://stackoverflow.com/a/65746143/96766 и https://stackoverflow.com/a/65749840/96766 (опубликованные @matthias-berndt и @tomer-shetah) работают в случае заблокированного потока, это не совсем то, что я ищу.
Позвольте мне сделать важное уточнение к вопросу. В моем случае будущее не в конечном счете завершено, но никогда не завершено. Например, когда
Future
получается из
Promise
который никогда не решается (никто не звонит
success
ни
failure
в теме). В этом случае предлагаемые решения по-прежнему блокируются бесконечно.
Есть ли способ обойти это для
AsyncSpec
не прибегая к использованию реального контекста выполнения на основе пула и
Await
на будущее?
3 ответа
Использовать
eventually
из
scalatest
- расширяет
Eventually
- Используйте следующий код, чтобы установить тайм-аут и интервал для проверки
import scala.concurrent.duration._
eventually(timeout(1 minutes), interval(5 seconds)) {
resultFuture.futureValue shouldBe ???
}
Использовать
AsyncTimeLimitedTests
черта.
https://www.scalatest.org/scaladoc/3.2.0/org/scalatest/concurrent/AsyncTimeLimitedTests.html
Вы можете использовать чертуTimeLimits
. Например, у вас может быть тестовый класс:
class MySpec extends AsyncFlatSpec with TimeLimits {
"this" should "fail" in {
failAfter(2.seconds) {
val resultFuture: Future[_] = Future {
Thread.sleep(3000)
}
assert(true)
}
}
"this" should "pass" in {
failAfter(2.seconds) {
val resultFuture: Future[_] = Future {
Thread.sleep(1000)
}
assert(true)
}
}
}