5

我有以下功能,我想测试:

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

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

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")))
    }
  )
4

6 回答 6

8

我想你肯定明白了。我要为其他有类似问题的人添加的唯一内容是您的示例还涉及环境类型,这是一个很好的讨论主题,但在某种程度上独立于如何使用 ZIO 测试测试效果是否按预期失败。

我在下面提供了一个最小示例,说明如何测试效果是否按预期失败。如上所述,您将调用run效果以获取退出值,然后使用Assertion.fails断言效果因检查异常而失败,Assertion.dies断言效果因未经检查的异常而失败,或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")))
        }
      )
    )
于 2019-11-01T22:45:44.177 回答
5

ZIO-Chat中 @adamfraser 的帮助下:

基本上在你的失败效果上调用 run 然后断言它是一个失败的 Assertion.fails。如果是未经检查的异常,则为 Assertion.dies。

我想我现在有一个很好的解决方案。

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")))
    )
  }

仍然欢迎其他解决方案。

于 2019-11-01T16:25:56.567 回答
4

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

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"))
        }
      )
    )
于 2019-11-12T16:17:12.060 回答
4

这是另一个紧凑的变体,使用assertM

object ExampleSpec extends DefaultRunnableSpec {
  def spec = suite("ExampleSpec")(
    testM("Example of testing for expected failure") {
      assertM(ZIO.fail("fail").run)(fails(equalTo("fail")))
    }
  )
}
于 2020-11-26T12:12:17.513 回答
1

如果您的错误是可抛出的,则equalsTo当它针对运行效果运行时会失败,因此您必须使用isSubtypeAssertion 来检查您是否收到正确的错误,这有点棘手:

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)))
        }
      )
    )
于 2021-03-08T18:55:37.233 回答
1

ZIO 2.0有一些变化:

  • 使用exit代替run
  • 使用test代替testM
  • assert有一个新的柯里化语法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"))
        )
    }
  )
)
于 2021-12-30T17:14:08.867 回答