Search code examples
scalafuturescalatest

Testing values returned by 2 Futures are equal to each other


To test Scala Future value I use this code :

  "Simple Test" should "Test Future" in {

    val futureData1: Future[Data] = MakeData()

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

This behaves as expected, how to test values that are contained in two Futures ?

For example, how to correctly modify below that tests two Futures:

  "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)
      }
      }
    }
    }
  }

Reading https://www.scalatest.org/user_guide/async_testing , there does not appear to be documentation describing the testing of multiple Futures.


Solution

  • Using map like this is unlikely to work the way you want it to - the assert inside map does not get run until the future is complete, which will likely happen after the test has already finished, and even if not, the exception from assert will be wrapped into a future and never actually thrown on the main thread, so the test will always pass.

    You seem to be using scalatest, so, it probably makes sense to mix in Eventually so that you can do these assertions property:

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

    Or, if you prefer ScalaFutures semantics (mix in ScalaFutures instead of Eventually), you can do:

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

    Or just

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

    That also makes the answer to your question quite obvious:

        assert(future1.futureValue == future2.futureValue)
    

    If you are still looking for a way to combine several futures together, you can use .zip (for two futures) or .sequence (for any number):

        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))