Как установить тайм-аут для пакета 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

  1. расширяет Eventually
  2. Используйте следующий код, чтобы установить тайм-аут и интервал для проверки
       import scala.concurrent.duration._
 eventually(timeout(1 minutes), interval(5 seconds)) {
    resultFuture.futureValue shouldBe ???
}

Вы можете использовать черту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)
    }
  }
}
Другие вопросы по тегам