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 puede afirmar errores esperados en el futuro sin bloqueo? Lo anterior no funciona, la excepción se produce antes de la intercept bloque.

InformationsquelleAutor flavian | 2014-01-04

6 Comentarios

  1. 14

    Nota: dejar esta respuesta porque el OP encontrado que es útil, pero para la Scala de Futuros de ver la otra respuesta.

    Esto es un poco boilerplated, 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, si usted tiene varias de futuros y desea que la primera no conformes futuro a fallar 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 de

    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 este no es amado respuesta.

  2. 153

    Sé que esto es probablemente un poco tarde, pero ScalaTest proporciona esta característica fuera de la caja (creo que desde la versión 2) mediante la mezcla en el ScalaFutures rasgo, o usando directamente en sus funciones de prueba. He aquí!

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

    O realizar algunas otras afirmaciones allí. Básicamente, si su futuro no falla como se espera, la prueba fallará. Si se produce un error, pero lanza una excepción diferente, la prueba fallará. Agradable y fácil! =]


    descarado de edición:

    También puede utilizar este método para probar cualquier cosa que devuelve un futuro:

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

    Más reciente edición!

    Quería actualizar esta respuesta con más información útil basada en las versiones más recientes de la Scala de prueba. Las distintas especificaciones de los rasgos de ahora todos tienen async apoyo, así que en lugar de ampliar, dicen, WordSpec, sería en lugar de extender AsyncWordSpec, y en lugar de confiar en la whenReady llamadas como en el anterior, solo que se asignan a través de sus futuros directamente en la prueba.

    Ejemplo:

    class SomeSpec extends Async[*]Spec with Matchers {
    
    ...
    
      test("some test") {
        someObject.funcThatReturnsAFutureOfSomething map { something =>
          //run assertions against the 'something' returned in the future
        }
      }
    }
    • Buen enfoque, +1. El aceptó respuesta es más útil, ya que estamos usando Twitter Futuros internamente.
    • ¿Por qué no a este trabajo de ambos Scala y Twitter futuros?
    • Debido a que Twitter Futuros son, ante todo, de un tipo diferente. He oído hablar de Twitter hablando de hacer extienden scala.conccurrent.En un futuro, pero para mi saber que no lo han hecho. La respuesta a esta pregunta ha sido incluido en nuestro util de la biblioteca, a disposición del público aquí: github.com/websudos/util.
    • No, no es tarde! Me alegro de que usted envió esta respuesta. El ScalaTest DSL toma algún tiempo para acostumbrarse.
    • Ah que poco failed de proyección es el truco, yo había tratado de whenReady sin éxito hasta que los señaló, gracias. Es ligeramente menos expresivo creo, pero si usted está hacia fuera para laconismo esto también funciona: f.failed.futureValue shouldBe a [SomeExceptionType].
    • Creo que esto es lo suficientemente útil que sería conveniente la creación de una nueva pregunta y la adición de inmediato como la respuesta y la aceptación del mismo
    • FTR, yo no uso ScalaTest y no tienen memoria acerca de mi respuesta. Pero es genial que el 41 ppl necesaria esta respuesta.
    • La capacidad se extiende el tiempo de espera puede ser útil: ScalaFutures.whenReady(f.error, el tiempo de espera(en escala(Intervalo(2, Segundos)))) { e => e shouldBe una [MyOwnException] }
    • ¿Cómo puedo importar shouldBe?

  3. 26

    Esta fue enterrado en un comentario así, pero Scalatest del FutureValues mixin tiene cubierto.

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

    • Esto es bastante agradable que es verdadera, pero la razón por la que me preocupaba acerca de la información interna es debido a que el código en cuestión se basa en realidad en Twitter Futuros como contraposición a la Scala de futuros.
    • Interesante. Parece un «TwitterFutures» mixin que hace la misma cosa que sería un buen complemento para ScalaTest si ellos no trabajan con twitter futuros.
    • Como este? cjwebb.github.io/blog/2015/02/02/scalatest de futuros
  4. 10

    ScalaTest 3.0 añade async versiones de la especificación de los rasgos 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
            }
        }
    }
  5. 0

    También puede probar esta Algo Simple y Corto

    test("some test throwing SQL Exception") {
          val f: Future[Something] = someObject.giveMeAFuture
          recoverToSucceededIf[SQLException](f)
        }
  6. 0

    Además Brian Baja del respuesta, he encontrado una buena explicación para recoverToSucceededIf. Este está disponible en todos los Async estilos (de ScalaTest 3):

    Error de futuros puede ser probado de dos maneras: utilizando recoverToSucceededIf o recoverToExceptionIf

    • recoverToSucceededIf se utiliza para afirmar que el tipo de la excepción el futuro termina en:
    "return UserNotFoundException" when {
           "the user does not exist" in {
             recoverToSucceededIf[UserNotFoundException](userService.findUser("1"))
           }
         }
    • recoverToExceptionIf es útil cuando se desea poner a prueba la excepción de los campos:
    "return UserAlreadyExistsException" when {
         "adding a user with existing username" in {
           recoverToExceptionIf[UserAlreadyExistsException] {
             userService.addUser(user)
           }.map { ex =>
             ex.message shouldBe s"User with username: $username already exists!"
           }
         }
       } 

    Ver todo el blog de Tudor Zgureanu

    ¿Qué hay de nuevo en ScalaTest 3

Dejar respuesta

Please enter your comment!
Please enter your name here