Значения тестирования, возвращаемые 2 фьючерсами, равны друг другу

#scala #future #scalatest

Вопрос:

Для проверки будущей ценности Scala я использую этот код :

   "Simple Test" should "Test Future" in {

    val futureData1: Future[Data] = MakeData()

    futureData1 map { data => { 
      assert(data.value == 2)
    }
    }
  }
 

Это ведет себя так, как ожидалось, как проверить значения, содержащиеся в двух фьючерсах ?

Например, как правильно изменить ниже, чтобы проверить два будущих:

   "Simple Test" should "Test Future" in {

    val futureData1: Future[Data] = MakeData()
    val futureData1: Future[Data] = MakeData()

    futureData1 map { data => {
      futureData1 map { data2 => {
        assert(data.value == data2.value)
      }
      }
    }
    }
  }
 

Чтение https://www.scalatest.org/user_guide/async_testing , похоже, нет документации, описывающей тестирование нескольких фьючерсов.

Комментарии:

1. Первым map должно быть a flatMap , и это, вероятно, выглядело бы лучше при использовании for

Ответ №1:

Используя map такой вряд ли будет работать так, как вы хотите — assert внутри карты не беги, пока будущее, что, вероятно, произойдет после того, как испытания уже закончены, а даже если и не исключение из утвердить будут обернуты в будущем и никогда не бросают на главном потоке, поэтому тест всегда проходит.

Похоже, вы используете scalatest, так что, вероятно, имеет смысл вмешаться, Eventually чтобы вы могли выполнять эти утверждения.:

     val f = doStuff()
    eventually {
      f.value shouldBe Some(Data(2))
    }
 

Или, если вы предпочитаете ScalaFutures семантику ( ScalaFutures вместо смешивания Eventually ), вы можете сделать:

     val f = doStuff()
    whenReady(f) { data => assert(data.value == 2) }
 

Или просто

     assert(doStuff().futureValue.value == 2) 
 

Это также делает ответ на ваш вопрос совершенно очевидным:

     assert(future1.futureValue == future2.futureValue)
 

Если вы все еще ищете способ объединить несколько фьючерсов вместе, вы можете использовать .zip (для двух фьючерсов) или .sequence (для любого числа):

     whenReady(future1 zip future2) { case (d1, d2) => assert(d1 == d2) }
    whenReady(Future.sequence(List(f1, f2, f3, f4)) { case first :: rest => 
        assert(rest.forall(_ == first))
 

Комментарии:

1. Или вы просто используете асинхронные спецификации, предоставляемые ScalaTest , которые ожидают Future[Assertion] и используют простой for

2. Или это … Что я ненавижу в scalatest, так это то, что он предлагает слишком много разных способов сделать одно и то же.