How zod-fixture can help with your test setups
Previously we've seen how zod can validate incoming HTTP requests and why that's helpful. In this blog post, we explore another use case for zod, in combination with zod-fixture.
zod-fixture
is a library that leverages a zod schema to generate new object instances that satisfy the configured schema.
We'll discover why this is useful later, but before we dive into the test cases, let's first define a zod
schema for a Customer
. The Customer
has a few properties and also has child objects for address
and pets
.
Now, imagine having a test case that checks if a collection of customers is rendered on the page.
Traditionally, most test cases look like a variant of the next test case. The important part here is at the top of the test, where you create the test fixtures that are used within the test.
I see this a lot in codebases because it's just the simplest way of creating instances, but it also has a couple of drawbacks.
The biggest chunk of the test consists of creating test fixtures, in this case, customer instances.
I didn't even take the time to model the child object address
and pets
because of this.
This makes the test cases look bigger than one would expect.
Because of this, the essence of the test gets lost and it might take a while to understand the test case.
But that isn't the only problem.
What happens when the Customer
model is updated? For example, when a property is added or removed?
With test setups like these, we need to update all the models.
This isn't very pleasant work, and it can also take some time to update.
As a counter measurement, we can introduce model factory methods to create the instances easier.
The refactored test looks as follows.
Instead of manually creating the customer instances, we invoke the createCustomer
method to create a new customer instance.
This is already better, and it solves the mentioned problems, but in my experience, it still isn't ideal.
As developers we tend to over-engineer the boring stuff, so there's a chance that these factories get complicated. More complicated than they need to be.
This beats the entire purpose of readable tests. We don't want to spend minutes figuring out how the setup is done.
For example, we could end up with factories that expect a lot of arguments just to tweak the properties of the model. Or worse, the factory contains complex conditions or structures to create an instance. When this happens, we end up in a similar situation as before, where many test cases need to be updated when we just change the model contract, or the way a model behaves.
Now that we understand the problem, let's see how zod
, specifically zod-fixture
, can give us a hand to create test fixtures to keep the test setup as simple as possible.
Because zod
holds the contracts of your models, we can make use of this data to generate the fixtures for your tests.
The easiest way to use zod-fixture
is by invoking the createFixture
method and passing the zod
schema as the argument.
Before we put this in a test, let's first take a look at the output just to give us an idea of what createFixture
does.
The first thing you can see is that createFixture
uses the schema to create an instance that complements the zod schema.
What isn't visible from this snippet is that you can't see that it does this randomly.
zod-fixture
assigns a random value to all properties, but the shape always looks identical.
For example, a string always has the property name as a prefix, and collections always contain 3 items. This makes it very convenient (and quick way) to new up instances at the start of a test case.
As you can see in the test below, it just takes 1 line of code to generate the customers
test fixture.
Conclusion link
We've seen how zod-fixture
helps us to keep the test setup to a bare minimum.
Instead of writing fixtures manually or writing code that does this for us, we can make use of the createFixture
method which does the heavy lifting for us.
By using zod-fixture
, we're also sure that the fixtures that are used within tests are also kept up-to-date with the zod schema, and thus also with the model interfaces that are used within the application.
While this blog post just shows the default behavior of zod-fixture
, it's also possible to change the way how values get generated. If you're interested and what to know more, please take a look at the docs.
Incoming links
Outgoing links
Feel free to update this blog post on GitHub, thanks in advance!
Join My Newsletter (WIP)
Join my weekly newsletter to receive my latest blog posts and bits, directly in your inbox.
Support me
I appreciate it if you would support me if have you enjoyed this post and found it useful, thank you in advance.