We've all experienced working on projects with multiple contributors, or even just a few. In such projects, unit tests are typically written by various individuals and sometimes have dependencies. For instance, it's common to encounter scenarios where consecutive tests mock the same functions. If these tests aren't written correctly, they can often lead to subsequent test failures due to inadequate mock cleanup.
Having encountered several instances of this issue, I've chosen to share a few tips for improving unit tests in Jest. These principles can also be applied to other testing frameworks like Mocha, Ava etc.
Clean up after others
When examining a single unit test file, it's impossible to predict which tests will be added in the future, potentially in separate modules and files. Therefore, it is highly recommended to ensure that our testing environment is as clean as possible before starting to write additional unit-tests.
This goal can be accomplished by utlizing the use of jest.resetAllMocks and jest.restoreAllMocks within our beforeAll block.
The difference between jest.restoreAllMocks and jest.resetAllMocks lies in the fact that jest.resetAllMocks internally invokes clearAllMocks() (which erases all mock usage data, such as mock.calls, mock.instances, mock.results and mock.contexts), it also reverts the mock function implementations to brand new instances created with jest.fn().
In contrast, jest.restoreAllMocks reverts all mocks to their original implementations, a functionality that is specific to mocks created using jest.spyOn.
An example on the utilization of jest.restoreAllMocks and jest.resetAllMocks
I also prefer use beforeAll to set my spies and mocks after cleaning the environment, and beforeEach to set the relevant mock responses.
let getDataSpy: jest.SpyInstance;
let getUserContentbyIdMock: jest.Mock;
beforeAll(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
getDataSpy = jest.spyOn(userDataSdk, "getData");
getUserContentbyIdMock = jest.fn();
});
beforeEach(() => {
getDataSpy.mockResolvedValue(getDataResponse);
getUserContentbyIdMock.mockResolvedValue(contentMockResponse);
});
Clean up after yourself
Just as we tidy up after others, it's important to ensure we clean up after each it block in our test file and also reset our environment before exiting our unit test file.
In order to do that, we need to use jest.restoreAllMocks and jest.resetAllMocks
An example on the utilization of jest.restoreAllMocks and jest.resetAllMocks after our tests complete
(It's enough to put jest.resetAllMocks() in afterEach because it will always run after the last it finishes in any case)
afterEach(() => {
jest.resetAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
});
Conclusion
Making sure our unit-test environment and setup is clean from previous data and mocks is a must, it ensures that our tests run in the isolated manner they are supposed to.
And as you can see, achieving this is quite simple and can save you a lot of frustration and debugging time in the future.
Also would like to recommend this post by Edwin Wong to learn more about the differences between jest.resetAllMocks, jest.restoreAllMocks and jest.clearAllMocks.
Top comments (0)