scala 如何用zio-test测试异常情况

zpjtge22  于 2023-06-23  发布在  Scala
关注(0)|答案(7)|浏览(155)

我有以下函数,我想测试:

def people(id: Int): RIO[R, People]

如果id有People,则此函数返回People。如果没有,则失败,例如:

IO.fail(ServiceException(s"No People with id $id"))

快乐的案例是这样的:

suite("Get a Person for an ID") (
    testM("get Luke Skywalker") {
      for {
        peopleRef <- Ref.make(Vector(People()))
        luke <- Swapi.>.people(1).provide(Test(peopleRef))
      } yield assert(luke, equalTo(People()))
    },

但是我如何测试失败的案例呢?我尝试了不同的东西,主要是类型不匹配。下面是一个尝试:

testM("get not existing People") {
      (for {
        peopleRef <- Ref.make(Vector(People()))
        failure = Swapi.>.people(2).provide(Test(peopleRef))
      } yield assertM(failure, fail(Cause.die(ServiceException(s"No People with id 2")))
    }
  )
kuuvgm7e

kuuvgm7e1#

我觉得你完全掌握了。对于其他有类似问题的人,我唯一想补充的是,你的例子也涉及到环境类型,这是一个很好的讨论主题,但在某种程度上与如何使用ZIO Test测试测试效果失败无关。
下面我提供了一个最小的例子来说明如何测试一个效果是否按预期失败。如上所述,您可以对效果调用run以获取退出值,然后使用Assertion.failsAssert效果失败并出现选中的异常,使用Assertion.diesAssert效果失败并出现未选中的异常,或使用Assertion.interrupted测试效果是否被中断。
另外请注意,您不必使用include equalTo("fail")。如果你只关心效果失败,你可以使用fails(anything)。如果你正在测试一个效果在一个指定的异常情况下死亡,你可以做一些像dies(isSubtype[IllegalArgumentException])这样的事情。
希望这有帮助!

import zio.test._
import zio.test.Assertion._
import zio.ZIO

object ExampleSpec
    extends DefaultRunnableSpec(
      suite("ExampleSpec")(
        testM("Example of testing for expected failure") {
          for {
            result <- ZIO.fail("fail")
          } yield assert(result, fails(equalTo("fail")))
        }
      )
    )
1zmg4dgp

1zmg4dgp2#

对于ZIO 2.0,有一些变化:

  • 使用exit代替run
  • 使用test代替testM
  • assert具有新的currying语法assert(result)(assertion)
import zio.test._
import zio.test.Assertion._
import zio.ZIO

object ExampleSpec extends DefaultRunnableSpec(
  suite("ExampleSpec")(
    test("Example of testing for expected failure") {
      for {
        result <- ZIO.fail("failureResult").exit
      } yield assert(result)(
          fails(equalTo("failureResult"))
        )
    }
  )
)
46qrfjad

46qrfjad3#

下面是ZIO 1.0使用assertM的另一个紧凑变体:

import zio._
import zio.test.Assertion.{equalTo, fails}
import zio.test._

object ExampleSpec extends DefaultRunnableSpec {
  def spec = suite("ExampleSpec")(
    testM("Example of testing for expected failure") {
      assertM(ZIO.fail("fail").run)(fails(equalTo("fail")))
    }
  )
}

在ZIO 2.0中,测试看起来非常相似:

import zio._
import zio.test._
import zio.test.Assertion.{equalTo, fails}

object ExampleSpec extends ZIOSpecDefault {
  def spec = suite("ExampleSpec ZIO 2.0")(
    test("Example of testing for expected failure in ZIO 2.0") {
      assertZIO(ZIO.fail("fail").exit)(fails(equalTo("fail")))
    }
  )
}
uajslkp6

uajslkp64#

ZIO-Chat中的@adamfraser的帮助下:
基本上,在你的失败效果上调用run,然后用Assertion. failsAssert它是一个失败。如果是未检查的异常,则Assertion.会死亡。
我想我现在有一个很好的解决方案。

testM("get not existing People") {
    for {
      peopleRef <- Ref.make(Vector(People()))
      failure <- Swapi.>.people(2).provide(Test(peopleRef)).run
    } yield assert(
      failure,
      fails(equalTo(ServiceException("No People with id 2")))
    )
  }

其他解决方案仍然受到欢迎。

lkaoscv7

lkaoscv75#

如果你的错误是可抛出的,那么equalsTo在运行时会失败,所以你必须使用isSubtypeAssert来检查你是否收到了正确的错误,这有点棘手:

import zio.test._
import zio.test.Assertion._
import zio.ZIO

object ExampleSpec
    extends DefaultRunnableSpec(
      suite("ExampleSpec")(
        testM("Example of testing for expected failure") {
          for {
            result <- ZIO.fail(new NoSuchElementException).run
          } yield assert(result, fails(isSubtype[NoSuchElementException](anything)))
        }
      )
    )
t1rydlwq

t1rydlwq6#

您还可以翻转错误和结果通道:

import zio.test._
import zio.test.Assertion._
import zio.ZIO

object ExampleSpec
    extends DefaultRunnableSpec(
      suite("ExampleSpec")(
        testM("Example of testing for expected failure") {
          for {
            result <- ZIO.fail("fail").flip
          } yield assert(result, equalTo("fail"))
        }
      )
    )
nszi6y05

nszi6y057#

所以我决定没有一个答案像我想要的那样清楚,chat gpt使用了scala test和ZIO(LOL)(ZIO 2.0)的混合。
我相信提问者不仅是想看看它是否失败了,而且还Assert信息是他们所期望的。最大的Assert是
failshasMessage(与equalTo耦合)。如果的文档中有更多这样的例子就好了,在此之前我希望这能有所帮助

import zio.{Scope, ZIO}
import zio.test.Assertion.{equalTo, fails, hasMessage}
import zio.test.{Spec, TestEnvironment, ZIOSpecDefault, assertZIO}

object ExampleSpec extends ZIOSpecDefault{
  override def spec: Spec[TestEnvironment with Scope, Any] = {
    suite("mapUpdatedMediaElements") {
      test("empty map of responses") {
        assertZIO(ZIO.fail(new RuntimeException("BROK3N")).exit)(fails(hasMessage(equalTo("BROK3N"))))
      }
    }
  }

}

相关问题