unit true test matchers lists flatspec failure exceptions example scala scalatest

true - scalatest suite



ScalaTest: Aserción de excepciones en futuros fallidos(sin bloqueo) (4)

import org.scalatest.{ FlatSpec, Matchers, ParallelTestExecution } import org.scalatest.concurrent.ScalaFutures import org.apache.thrift.TApplicationException class Test extends FlatSpec with Matchers with ScalaFutures with ParallelTestExecution { it should "throw org.apache.thrift.TApplicationException for invalid Ids" in { val future: Future[Response] = ThriftClient.thriftRequest whenReady(future) { res => { intercept[TApplicationException] { } } } } }

Pregunta: ¿Cómo se afirman las fallas esperadas en los futuros sin bloqueo? Lo anterior no funciona, la excepción se lanza antes del bloque de intercept .


Nota: al dejar esta respuesta porque OP la encontró útil, pero para Scala Futures, vea la otra respuesta.

Esto es un poco repetitivo, pero Waiter de AsyncAssertions :

import org.scalatest.{ FlatSpec, Matchers, ParallelTestExecution } import org.scalatest.concurrent.{ ScalaFutures, AsyncAssertions, PatienceConfiguration } import concurrent.Future import concurrent.ExecutionContext.Implicits._ import util._ class Test extends FlatSpec with Matchers with ScalaFutures with ParallelTestExecution with AsyncAssertions { it should "throw for invalid Ids" in { val f: Future[Int] = new Goof().goof val w = new Waiter f onComplete { case Failure(e) => w(throw e); w.dismiss() case Success(_) => w.dismiss() } intercept[UnsupportedOperationException] { w.await } } }

dado

import concurrent.Future import concurrent.ExecutionContext.Implicits._ class Goof { def goof(delay: Int = 1): Future[Int] = Future { Thread sleep delay * 1000L throw new UnsupportedOperationException } def goofy(delay: Int = 1): Future[Int] = Future { Thread sleep delay * 1000L throw new NullPointerException } def foog(delay: Int = 1): Future[Int] = Future { Thread sleep delay * 1000L 7 } }

En otras palabras,

class Test extends FlatSpec with Matchers with ScalaFutures with ParallelTestExecution with AsyncAssertions { it should "throw for invalid Ids" in { val f: Future[Int] = new Goof().goof import Helper._ f.failing[UnsupportedOperationException] } } object Helper { implicit class Failing[A](val f: Future[A]) extends Assertions with AsyncAssertions { def failing[T <: Throwable](implicit m: Manifest[T]) = { val w = new Waiter f onComplete { case Failure(e) => w(throw e); w.dismiss() case Success(_) => w.dismiss() } intercept[T] { w.await } } } }

O bien, si tiene futuros múltiples y desea que el primer futuro no conforme fracase en la prueba:

trait FailHelper extends Assertions with AsyncAssertions with PatienceConfiguration { def failingWith[T <: Throwable : Manifest](fs: Future[_]*)(implicit p: PatienceConfig) { val count = new java.util.concurrent.atomic.AtomicInteger(fs.size) val w = new Waiter for (f <- fs) f onComplete { case Success(i) => w(intercept[T](i)) println(s"Bad success $i") w.dismiss() case Failure(e: T) => println(s"Failed $e OK, count ${count.get}") w(intercept[T](throw e)) if (count.decrementAndGet == 0) w.dismiss() case Failure(e) => println(s"Failed $e Bad") w(intercept[T](throw e)) w.dismiss() } w.await()(p) } }

con el uso

class Test extends FlatSpec with Matchers with ScalaFutures with ParallelTestExecution with FailHelper { it should "throw for invalid Ids" in { val sut = new Goof() import sut._ val patienceConfig = null // shadow the implicit implicit val p = PatienceConfig(timeout = 10 seconds) // all should fail this way //failingWith[UnsupportedOperationException](goof(), goofy(3), foog(5)) //failingWith[UnsupportedOperationException](goof(), foog(5)) failingWith[UnsupportedOperationException](goof(), goof(2), goof(3)) } }

Inspirado por esta respuesta no deseada .


Esto también fue enterrado en un comentario, pero la mezcla de FutureValues ​​de Scalatest lo tiene cubierto.

Solo use f.failed.futureValue shouldBe an[TApplicationException]


Sé que esto es probablemente un poco tarde, pero ScalaTest ofrece esta característica de inmediato (creo que desde la versión 2) al mezclar el rasgo de ScalaFutures o usarlo directamente en las funciones de prueba. ¡Mirad!

test("some test") { val f: Future[Something] = someObject.giveMeAFuture ScalaFutures.whenReady(f.failed) { e => e shouldBe a [SomeExceptionType] } }

O puede realizar algunas otras afirmaciones allí. Básicamente, si su futuro no falla como espera, la prueba fallará. Si falla, pero arroja una excepción diferente, la prueba fallará. ¡Bonito y fácil! =]

descarada edición:

También puede usar este método para probar cualquier cosa que devuelva un futuro:

test("some test") { val f: Future[Something] = someObject.giveMeAFuture ScalaFutures.whenReady(f) { s => // run assertions against the object returned in the future } }


ScalaTest 3.0 agrega versiones asincrónicas de los rasgos de especificación como AsyncFreeSpec :

import org.scalatest.{AsyncFlatSpec, Matchers} import scala.concurrent.Future class ScratchSpec extends AsyncFlatSpec with Matchers { def thriftRequest = Future { throw new Exception() } it should "throw exception" in { recoverToSucceededIf[Exception] { thriftRequest } } }