2
votes

Comment tester un cas d'exception avec zio-test

J'ai la fonction suivante, que je souhaite tester:

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

Cette fonction renvoie People s'il y en a un pour cet id , resp. échoue sinon, comme:

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()))
    },

Le cas heureux fonctionne, comme:

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

Mais comment puis-je tester le cas d'échec? J'ai essayé différentes choses, la plupart du temps les types ne correspondent pas. Voici une tentative:

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


0 commentaires

4 Réponses :


5
votes

Avec l'aide de @adamfraser dans le ZIO-Chat :

Fondamentalement, appelez run sur votre effet d'échec, puis affirmez qu'il s'agit d'un échec avec Assertion.fails. Ou Assertion.dies s'il s'agit d'une exception non vérifiée.

Je pense que j'ai maintenant une bonne solution.

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

D'autres solutions sont toujours les bienvenues.


0 commentaires

6
votes

Je pense que vous l'avez définitivement. La seule chose que j'ajouterais pour les autres avec des questions similaires est que votre exemple implique également un type d'environnement, qui est un excellent sujet de discussion mais quelque peu indépendant de la façon de tester qu'un effet échoue comme prévu en utilisant ZIO Test.

J'ai inclus ci-dessous un exemple minimal de la façon de tester qu'un effet échoue comme prévu. Comme mentionné ci-dessus, vous appelleriez run sur l'effet pour obtenir une valeur de sortie, puis utilisez Assertion.fails pour affirmer que l'effet échoue avec une exception vérifiée, Assertion.dies pour affirmer que l'effet échoue avec une exception non vérifiée, ou Assertion.interrupted pour tester qu'un effet a été interrompu.

Notez également que vous ne devez pas utiliser include equalTo("fail") . Si tout ce qui vous importe, c'est que l'effet a échoué, vous pouvez simplement utiliser fails(anything) . Si vous testez qu'un effet meurt avec une exception spécifiée, vous pouvez faire quelque chose comme dies(isSubtype[IllegalArgumentException]) .

J'espère que cela t'aides!

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


2 commentaires

Pour mémoire, cet exemple ne fonctionne pas pour moi. J'essaie de trouver la façon la plus idiomatique de tester les échecs attendus et votre exemple semble que cela devrait fonctionner, mais il ne se compile pas pour moi. Erreur: incompatibilité de type (11, 37); trouvé: zio.test.Assertion [zio.Exit [Any, Any]] requis: zio.test.Assertion [String]} yield assert (result, failed (equalTo ("fail")))


Il semble que j'avais besoin d'ajouter .runs à l'effet afin d'utiliser l'assertion d' fails , c'est-à-dire ZIO.fail("fail").run



1
votes

Vous pouvez également inverser les canaux d'erreur et de résultat:

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


1 commentaires

gentil, merci - a peut-être besoin d'un commentaire pour être clair;)



1
votes

Voici une autre variante compacte utilisant assertM :

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


0 commentaires