Article thumbnail

Using dependency injection pattern to improve fixtures

4m
frontend
testing
quality

Intro

Optimize Jest fixtures using dependency injection. Inject environment functions to streamline code, ease test creation.

The problem to solve

In previous lesson - ⭐ Mocking environment variables, we created a nice working fixture that reduces lines of code when we write tests.

However, the result is not "ideal". Still, we may reduce and remove some responsibilities from developers. Check the following code to understand what I mean:

Loading

So, imagine a situation when you forget to add afterEach and fixture.restore() statement in one of your tests... It may happen because the fixture.restore() call cleans up all mocks in the environment object. Yea, it will be pretty hard to spot what is causing false positives or false negatives in our tests.

Good news! Dependency injection pattern will fix all our problems 💨.

The dependency injection pattern

Let's explain it with another example not connected with our problem to understand the basic idea. Imagine that you've installed a library called "users-list" which is a React component with sorting capabilities (yea, really complicated :P).

The implementation of component looks like this (remember it's a library code - in your app you just installed it):

Loading

Now, imagine that the implementation of this component sorting mechanism is broken - looks like the sort function from Lodash has a bug!

Loading

So, what's now? What kind of options do you have? You can try to find another lib, copy the lib source code to your code, wait for a fix, or implement it completely on your own... All of these options are time-consuming and it's just a sort function bug...

If the author of the library would add one small change, we would not have to do anything... Check the code below to understand how we may improve it:

Loading

Instead of relying on and being coupled with Lodash without the option to override sort mechanism, we've added UsersListProps interface, to be able to change sorting mechanism. That's how dependency injection pattern works in its simplest form.

You need to pass a function that implements the required contract - in our case specified via TypeScript interface. Now, we still are coupled with Lodash, but we may replace it from consumer code, not inside UsersList library implementation (in addition we improved our code from the SOLID perspective - the Open/Close principle.

The last change must be implemented in the consumer component and our little bug will be fixed without any additional effort.

Loading

Dependency injection pattern may be implemented in many different ways. We may use injection tokens and more advanced mechanisms. The presented approach is the simplest implementation of it!

Fixing our fixture with dependency injection

We'll use the same technique as above. We'll pass afterEach function from Jest to our fixture. When the fixture is called the first time, it will trigger afterEach, so in test files all of these statements will be removed.

Loading

First, we added an additional type to define the signature of afterEach function. We used higher order function pattern and closure mechanism to be able to call our fixture function twice.

Second, with injected afterEach and passed the key that is required. Thanks to the closure, afterEach callback will be remembered and we'll be able to do stuff like this:

Loading

Small note

If you would like to add additional logic to afterEach and you're using this fixture - don't worry about anything, the Jest will run as many callbacks as you define :).

Loading

So, you will have always called all defined afterEach functions, the one that we're passing and the others defined in tests. Thanks to that you're not limited to only one afterEach call.

The final result

Loading

Conclusions and thoughts

As you saw we've added a nice improvement for developers that reduces the code that they need to write and the responsibility to "remember". In this particular fixture, it was just 3 lines of code and one responsibility, but in more advanced ones it may be much more!

To see more advanced fixtures you may read ⭐ Creating fixture for MSW to reduce boilerplate and setup.

I create content regularly!

I hope you found my post interesting. If so, maybe you'll take a peek at my LinkedIn, where I publish posts daily.

Comments

Add your honest opinion about this article and help us improve the content.

created: 10-04-2023
updated: 10-05-2023