Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test methods that return Future?

Tags:

scala

specs2

I'd like to test a method that returns a Future. My attempts were as follows:

import  org.specs2.mutable.Specification
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

class AsyncWebClientSpec extends Specification{

  "WebClient when downloading images" should {
    "for a valid link return non-zero content " in {
      val testImage = AsyncWebClient.get("https://www.google.cz/images/srpr/logo11ww.png")
      testImage.onComplete { res => 
        res match {
          case Success(image) => image must not have length(0)
          case _ =>
        }
        AsyncWebClient.shutDown
      }
    }
  }
}

Apart from the fact that I am unable to make this code work I guess that there could be a better way of testing a futures with a Future-oriented matcher.

How to do it properly in specs2?

like image 874
jaksky Avatar asked Jan 02 '15 23:01

jaksky


Video Answer


3 Answers

You can use the Matcher.await method to transform a Matcher[T] into a Matcher[Future[T]]:

val testImage: Future[String] =
   AsyncWebClient.get("https://www.google.cz/images/srpr/logo11ww.png")  

// you must specify size[String] here to help type inference
testImage must not have size[String](0).await

// you can also specify a number of retries and duration between retries
testImage must not have size[String](0).await(retries = 2, timeout = 2.seconds)

// you might also want to check exceptions in case of a failure
testImage must throwAn[Exception].await
like image 185
Eric Avatar answered Oct 21 '22 10:10

Eric


Took me awhile to find this so thought I'd share. I should've read the release notes. In specs2 v3.5, it is required to use implicit ExecutionEnv to use await for future. This can also be used for future transformation (i.e. map) see http://notes.implicit.ly/post/116619383574/specs2-3-5.

excerpt from there for quick reference:

import org.specs2.concurrent.ExecutionEnv

class MySpec extends mutable.Specification {
  "test of a Scala Future" >> { implicit ee: ExecutionEnv =>
    Future(1) must be_>(0).await
  }
}
like image 14
subandroid Avatar answered Oct 21 '22 10:10

subandroid


Await is an anti pattern. Shouldn't ever use it. You can use traits like ScalaFutures, IntegrationPatience, and Eventually.

whenReady does the magic you are looking for.

Example:

import org.specs2.mutable.Specification
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import scala.concurrent.Future

class AsyncWebClientSpec extends Specification
    with ScalaFutures
    with IntegrationPatience {

    "WebClient when downloading images" should {

        "for a valid link return non-zero content " in {

            whenReady(Future.successful("Done")){ testImage =>

                testImage must be equalTo "Done"           
                // Do whatever you need
            }

        }
    }
}
like image 10
epinal Avatar answered Oct 21 '22 10:10

epinal