Как проверить случай исключения с помощью zio-test
У меня есть следующая функция, которую я хочу протестировать:
def people(id: Int): RIO[R, People]
Эта функция возвращает людей, если для этого есть id
, соотв. не работает, если нет, например:
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")))
}
)
7 ответов
Я думаю, ты определенно понял. Единственное, что я хотел бы добавить для других с подобными вопросами, это то, что ваш пример также включает тип среды, который является отличной темой для обсуждения, но в некоторой степени не зависит от того, как проверить, что эффект терпит неудачу, как ожидалось, с помощью ZIO Test.
Ниже я привел минимальный пример того, как проверить, что эффект не работает должным образом. Как упоминалось выше, вы бы позвонили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")))
}
)
)
Вот еще один компактный вариант с использованием
assertM
:
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 есть несколько изменений:
- Использовать
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"))
)
}
)
)
если ваша ошибка выбрасывается,
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)))
}
)
)
С помощью @adamfraser в ZIO -Chat:
Обычно вызывайте 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")))
)
}
Другие решения по-прежнему приветствуются.
Вы также можете перевернуть каналы ошибок и результатов:
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 использовал тест Scala, смешанный с ZIO (LOL) (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"))))
}
}
}
}