DEV Community

Cover image for How to Mock dependencies with Jest
Dany Paredes for This is Learning

Posted on

How to Mock dependencies with Jest

When we want to test our code, some things have dependencies inside, and you don't want to call these stuff. You won't be sure your code works, not external dependencies or external code not related to my code.

Today we will add tests into our example weather app using Jest and Mock the dependencies.

The app

Our example app has two principal codes, the weatherAPI.js and showWeather.js; the showWeather uses weatherAPi.js code to display the data.

The weatherAPI.js

const getWeather = (format) => {
    const min = format = 'C' ? 50 : 100;
    return  50;
}

module.exports = { getWeather}
Enter fullscreen mode Exit fullscreen mode

The showWeather.js

const weatherAPI = require('./weatherAPI');

const messageWeather = () => {
    let weather = weatherAPI.getWeather('C');
    return `Today weather is ${weather}, have a nice day!`
}

module.exports = { messageWeather }
Enter fullscreen mode Exit fullscreen mode

We have a clear idea about our app, and the next step is to add tests for showWeather code.

You see the final example code from GitHub repo https://github.com/danywalls/02-mocking-code

Writing the test

We use jest functions test to declare our test and the assertion functions expect and toBe matchers.

The idea focuses on mocking; to read more about the assertion functions, feel free to read the official documentation.

const weatherAPI = require('./weatherAPI');
const { messageWeather } = require('./showWeather');

test('should return weather message with celsius temperature', () => {
    const result = messageWeather();
    const expected = `Today weather is 50, have a nice day!`;
    expect(result).toBe(expected);
})

Enter fullscreen mode Exit fullscreen mode

Run our test npx jest, and all test works using our mocks!

 PASS  ./showWeather.test.js
  Show Weather functions
    โœ“ should return weather message with celsius temperature (3 ms)
    โœ“ Should return async weather (1 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.383 s, estimated 1 s
Enter fullscreen mode Exit fullscreen mode

Nice, but our test calls the getWeather using the actual code, and my test only needs to cover the showWeather code.

How to fake the weatherAPI methods?

Jest provides a few ways to mock the weatherAPI methods.

We will use the three options, with the same result but each, you can pick which is better for you.

Override functions with jest.fn

The easiest way is to reassign the getWeather method and assign a jest.fn mock function, we update the test with the following points.

  • assign jest.fn and return 20 by default.
  • validate the getWeather method to get the C parameter.
  • validate the result and expect are equal.
test('should return weather message with celsius temperature', () => {
    weatherAPI.getWeather = jest.fn((format) => `20`);

    expect(weatherAPI.getWeather).toHaveBeenCalledWith('C');
    const result = messageWeather();
    const expected = `Today weather is 20, have a nice day!`;

    expect(weatherAPI.getWeather).toHaveBeenCalledWith('C');
    expect(result).toBe(expected);
    weatherAPI.getWeather.mockRestore();
})

Enter fullscreen mode Exit fullscreen mode

The function mockRestore assigns the original value to getWeather function.

Use jest.spyOn

The spyOn help us to assign a mock function to the object, in our case, the weatherAPI object.

The spyOn override and the function getWeather mock have the mock implementation function to return the simulated value.

    jest.spyOn(weatherAPI, 'getWeather')
    weatherAPI.getWeather.mockImplementation((format) => `20`)

    const result = messageWeather();
    const expected = `Today weather is 20, have a nice day!`;

    expect(weatherAPI.getWeather).toHaveBeenCalledWith('C');
    expect(result).toBe(expected);

    weatherAPI.getWeather.mockRestore();

Enter fullscreen mode Exit fullscreen mode

Mock the module

Instead of mocking every function, jest helps us mimic the entire module using jest.mock.

Create mocks directory into the same path of the file to mock, export the functions, and create the module's name in our case weatherAPI.

module.exports = {
    getWeather: jest.fn((format) => `20`)
}
Enter fullscreen mode Exit fullscreen mode

In our test, the to jest uses the mock module with jest.mock.

jest.mock('./weatherAPI');
test('should return weather message with celsius temperature', () => {

    const result = messageWeather();
    const expected = `Today weather is 20, have a nice day!`;
    expect(weatherAPI.getWeather).toHaveBeenCalledWith('C');
    expect(result).toBe(expected);
    weatherAPI.getWeather.mockRestore();

})

Enter fullscreen mode Exit fullscreen mode

Testing async functions

Async functions are very common in our code, lets add a new function promise into the weatherAPI and use it, in the showWeather.js.

Read more about async and await keyword

const getMetaWeather = async () => {
    return new Promise((resolve) => {
        resolve('Summer time!')
    })

}

module.exports = { getWeather, getMetaWeather}
Enter fullscreen mode Exit fullscreen mode

The getMetaWeather function is a promise, to use it in our new function showWeatherStatus, we use the await and async to wait for the getMetaWeather response.

const showWeatherStatus = async () => {
    let weather =  await weatherAPI.getMetaWeather();
    return `${weather}, Enjoy!`
}

module.exports = { messageWeather, showWeatherStatus }
Enter fullscreen mode Exit fullscreen mode

The next step is to update our test to cover the showWeatherStatus, editing the mocks/weatherAPI.js to return the mock version of the getMetaWeather function returns a promise with the mock data.

getMetaWeather: jest.fn(() => new Promise((resolve) => resolve('Great day') ))
Enter fullscreen mode Exit fullscreen mode

We create a new test for async weather status, but using the async and await keyword because we update the mocks, our tests automatic will get the mocking example :)

test('Should return async weather status', async () => {
    const result = await showWeatherStatus();
    const expected = 'Great day, Enjoy!';
    expect(result).toBe(expected);
})
Enter fullscreen mode Exit fullscreen mode

Perfect, run your test npx jest and all cases works using mock data.

 PASS  ./showWeather.test.js
  Show Weather functions
    โœ“ should return weather message with celsius temperature (3 ms)
    โœ“ Should return async weather (1 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.383 s, estimated 1 s
Enter fullscreen mode Exit fullscreen mode

Final

Jest makes it easy to test our code and external dependencies. I recommend using the mocks overriding the complete module because it makes it easy to update the mocks and read the tests because it only has assertions methods.

If you want to read more about mocking with jest, please read the official documentation.

Photo by Christian Gertenbach on Unsplash

Discussion (0)