Road to ZIO[N]: chapter 3, testing the Domain

Manuel Rodríguez
3 min readMar 26, 2022

--

I got to keep on walking
On the road to Zion

In this chapter of our Road To ZIO[n] we’ll see how we can test our Domain layer. We’ll be incorporated the lessons learned in the “Testing with Refined Types” section of this article and apply them to the ZIO test library.

Note that most of the knowledge applied here comes from THIS GREAT ARTICLE by Pavels Sisojevs which is basically this same one but better explained, so props to him.

Building generators

The first that I discovered when learning to test in ZIO is that the framework is extremely similar to scalacheck/scalatest. In particular, there is property based testing! So my first step was building generators for the Types that we are using, which in this case is just “User”. I noticed that the base generators are way more limited that in scalatest though, so I build a couple auxiliary generators. This is pretty straightforward.

The next step is making sure that this does in fact work as expected.

Let’s have a look at this:

  • line 2&3: this is how we run the tests
  • line 4: give the group of tests a name
  • line 5: give the test a name
  • line 6: define the generators that will be used in the test
  • line 7: specify what is the success condition

Note that this is run synchronously and there are no effects around, so we can use “check” and “assert”. In a chapter to come we’ll use “checkM” and “assertM” as we will be wrapping things into ZIO.

Testing the model

As we saw in chapter 2, domain objects are built using a builder. We need to test it, of course.

This is the same as in the previous test. The only important thing is that we are checking that the returned type on the “build” function is correct.

Testing the Service

Now we’ll be testing the UserService class. I’m posting it here for completion, although it was described in a previous chapter.

The key thing here is that the methods here need a “UserPersistence” layer, which is defined in the “port” package like “type UserPersistence = Has[StoragePort]”

Creating a DB layer for the tests

The methods are accessing the environment -which in my head is like a stack with all the variables and methods available at that point- and looking for specific functions. we need to provide them in the testing environment. This looks like:

We are doing two things here. First we define a vector-based simple DB, and then we define the layer so we can use it whenever we want to have a “UserPersistence”.

Testing the Service

This is used in the testing class:

This is like the first test that we saw but with some key differences:

  • line 25: here we say “whenever you need a UserPersistence layer in the TestEnvironment, use TestDB.layer” which is the one created in the previous section
  • line 7: assertions now have to deal with effects. That is why use “assertM”
  • line 10: checkM for the same reason
  • line 14: here we are inside the for comprehension so we can use “assert”

And that’s pretty much it! We — or at least myself — have learned how to test the Domain layer using property-based testing and ZLayers, so it’s been a great step towards a deep understanding of ZIO.

--

--

Manuel Rodríguez

Developer at New Relic. This is where I keep the cool stuff that I learn in my free time