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] {
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
问题:如何在没有阻塞的情况下断言期货中的预期失败?以上不起作用,在intercept块之前抛出异常.
Ste*_*ari 153
我知道这可能有点晚了,但是ScalaTest通过混合ScalaFutures特性或直接在测试函数中使用它提供了开箱即用的这个功能(我相信自版本2).看哪!
test("some test") {
val f: Future[Something] = someObject.giveMeAFuture
ScalaFutures.whenReady(f.failed) { e =>
e shouldBe a [SomeExceptionType]
}
}
Run Code Online (Sandbox Code Playgroud)
或者您可以在那里执行其他一些断言.基本上,如果你的未来没有像你期望的那样失败,那么测试就会失败.如果失败,但抛出不同的异常,则测试将失败.好,易于!=]
厚脸皮编辑:
您还可以使用此方法测试返回未来的任何内容:
test("some test") {
val f: Future[Something] = someObject.giveMeAFuture
ScalaFutures.whenReady(f) { s =>
// run assertions against the object returned in the future
}
}
Run Code Online (Sandbox Code Playgroud)
eas*_*sel 26
这也被隐藏在评论中,但是Scalatest的FutureValues mixin让你满意.
只是用 f.failed.futureValue shouldBe an[TApplicationException]
som*_*ytt 14
这有点花洒,但Waiter来自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
}
}
}
Run Code Online (Sandbox Code Playgroud)
特定
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
}
}
Run Code Online (Sandbox Code Playgroud)
换一种说法,
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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
或者,如果您有多个期货,并且您希望第一个不合格的未来未通过测试:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
用法
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))
}
}
Run Code Online (Sandbox Code Playgroud)
灵感来自这个不受欢迎的答案.
Bri*_*Low 10
ScalaTest 3.0添加了规范特征的异步版本,如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
}
}
}
Run Code Online (Sandbox Code Playgroud)
除了Brian Low 的回答之外,我还找到了一个很好的解释recoverToSucceededIf。这在所有异步样式中都可用(来自ScalaTest 3):
失败的期货可以通过两种方式进行测试:使用recoverToSucceededIf或recoverToExceptionIf
recoverToSucceededIf用于断言未来结束的异常类型:"return UserNotFoundException" when {\n "the user does not exist" in {\n recoverToSucceededIf[UserNotFoundException](userService.findUser("1"))\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n\nrecoverToExceptionIf当您想要测试某些异常的字段时非常有用:"return UserAlreadyExistsException" when {\n "adding a user with existing username" in {\n recoverToExceptionIf[UserAlreadyExistsException] {\n userService.addUser(user)\n }.map { ex =>\n ex.message shouldBe s"User with username: $username already exists!"\n }\n }\n } \nRun Code Online (Sandbox Code Playgroud)\n\n查看 Tudor Zgureanu 的整个博客\n\xe2\x80\x94\nScalaTest 3 中的新增功能
\n| 归档时间: |
|
| 查看次数: |
25215 次 |
| 最近记录: |