我有以下函数,我想测试一下:
def people(id: Int): RIO[R, People]
如果该id
有一个,则此函数返回 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")))
}
)
我想你肯定明白了。对于有类似问题的其他人,我唯一要补充的是,您的示例还涉及环境类型,这是一个很好的讨论主题,但在某种程度上独立于如何使用 ZIO Test 测试效果是否按预期失败。
我在下面提供了一个最小示例,说明如何测试效果是否按预期失败。如上所述,您将对效果调用run
以获取退出值,然后使用Assertion.fails
断言效果失败并出现已检查的异常,Assertion.dies
断言效果因未检查的异常而失败,或者Assertion.interrupted
来测试效果是否被中断。
另请注意,您不必使用 包含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")))
}
)
)
对于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"))
)
}
)
)
这是另一个使用 ZIO 1.0assertM
的紧凑变体:
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")))
}
)
}
如果你的错误是可抛出的,那么当equalsTo
在运行效果时失败,所以你必须使用isSubtype
断言来检查你是否收到了正确的错误,这有点棘手:
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)))
}
)
)
在ZIO-Chat中@adamfraser的帮助下:
基本上,调用运行你的失败效果,然后断言它是断言失败的断言。 或者 断言.死亡 如果它是一个未经检查的异常。
我想我现在有一个很好的解决方案。
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")))
)
}
其他解决方案仍然受到欢迎。
您还可以翻转错误和结果通道:
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"))
}
)
)
所以我决定没有一个答案像我想要的那样清楚,聊天 gpt 正在使用与 ZIO 混合的 scala 测试 (大声笑) (ZIO 2.0
)
我相信提问者不仅要看它是否失败,还要断言信息是他们所期望的。那么最大的断言是
fails
和hasMessage
(加上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"))))
}
}
}
}