How to Test Effects in ZIO | An Introduction to ZIO Test

Reading Time: 4 minutes

In this blog, we’ll understand how to test ZIO effects using the ZIO Test library. Also, we’ll learn about some of the common assertions and a nice feature of ZIO Test which is test aspects.

What is ZIO Test?

ZIO Test is a testing library that makes it easy to test effectual programs. It treats effects as first class values and leverages the full power of ZIO.

To get started with ZIO Test, first add it as a dependency in your build.sbt

libraryDependencies ++= Seq(
  "dev.zio" %% "zio-test" % zioVersion,
  "dev.zio" %% "zio-test-sbt" % zioVersion,
)

Writing First Test

We can write our first test by extending DefaultRunnableSpec and implementing its spec method.

Each collection of tests is represented as a spec that can either be a test or a suite containing one or more other specs.

We write tests using the assert operator, which takes first a value that we are making an assertion about and then an assertion that we expect to hold for that value. Here we are using the simple equalTo assertion which just expects the value to be equal to the argument to equalTo, but we can have a variety of other assertions as well to express more complicated expectations.

The test above does not involve any ZIO effects. So let’s see how we can test our ZIO effects using this ZIO Test library:

Beyond replacing 5 * 5 with ZIO.succeed(5 * 5) the only change we made is replacing test with testM and assert with assertM.

Replacing test with testM tells the test framework that the test will return a ZIO effect.

Similarly replacing assert with assertM indicates that the left hand side of the assertion will be a ZIO effect and the test framework should run the left hand side and compare its result to the expectation on the right hand side.

There is nothing magical about assertM here. In fact we can replace assertM with assert using map or a for comprehension.

All three ways of writing this test are equivalent.

In general, we find that using assertM is most readable when the entire test fits on a single line and using a for comprehension is preferable otherwise, but you can pick the style that works for you.

You can also use && and || to combine multiple assert statements using logical conjunction and disjunction or ! to negate an assertion.

Other Common Assertions

The equalTo assertion that we used in above examples is one of the most basic assertion but there’s also a variety of other assertions in the Assertion companion object from zio.test package which are useful in certain situations.

Assertions can be specialized for particular data types. For example, when working with collections we may want to assert that two collections have the same elements, even if they do not appear in identical order. We can easily do this using the hasSameElements assertion.

Another assertion that is particularly useful is the fails assertion, which allows us to assert that an effect fails with a particular value. We can use this by first calling run on our effect to obtain a ZIO effect that succeeds or fails with an Exit value representing the result of the original effect and then using the fails assertion with that Exit value.

In the example above, the fails assertion required that the result of the ZIO effect be a failure and then allowed us to provide another argument to make a more specific assertion about what that failure value must be. In this case we just used the isUnit assertion which is a shorthand for equalTo(()) but we could have used whatever assertion we wanted.

Another useful assertion is anything that you can use to express an assertion that is always true.

Test Aspects

ZIO Test provide users with another nice feature which is test aspects.

Test aspects modify some aspect of how tests are executed. They can be used to modify individual tests or even entire suites that you have created. Here are some of important test aspects:

  • nonFlaky – repeats a test n times to make sure it is not flaky
  • timeout – time out a test after a specified duration
  • ignore – mark test as ignored
  • failing – specify that we expect a test to fail
  • jvmOnly – runs a test only on JVM platform
  • after – runs an effect after a test
  • flaky – retries a test until success

Test aspects are applied to a test or suite using the @@ operator: Here are some examples:

That’s all for this blog. I hope you find it useful and easy to understand. There is much more to learn about ZIO Test but this should give you the tools you need to start writing your own tests for ZIO programs.

For more blogs related to ZIO, visit Knoldus Blogs.

References

Written by 

Prateek Gupta is a Software Consultant at Knoldus Inc. He likes to explore new technologies and believes in writing clean code. He has a good understanding of programming languages like Java and Scala. He also has good time management skills. In his leisure time, he like to do singing and watch SciFi movies.