How To Mock Service With Ribbonclient Configuration
I recently institute myself working in a Javascript codebase where I needed to implement new Jest tests. I knew very piffling at the time about writing tests, so I looked to Jest docs and existing patterns in the codebase to effigy out all-time practices and how to do it. It was adequately straightforward, and I even plant myself enjoying testing. But I could not for the life of me reliably mock an API call.
The docs seemed clear, and the existing code appeared to have practiced patterns, only there were but so many ways to mock things. The existing tests used all sorts of mocking methods such as jest.genMockFromModule()
, jest.spyOn()
, and jest.mock()
. Sometimes the mocks were inline, sometimes they were in variables, and sometimes they were imported and exported in magical means from mysterious __mocks__
folders. I used these techniques interchangeably every fourth dimension I got a flare-up of confidence in agreement, only to find myself stumbling over the dissimilar methods and their effects. I had no idea what I was doing.
The event
The issue was that I was trying to learn how to run before I even knew how to walk. Jest has many powerful ways to mock functions and optimize those mocks, but they're all useless if you don't know how to make a simple mock in the first place. And while the Jest documentation provides a lot of great insight and techniques, I couldn't figure out where to start.
In this commodity, I promise to give you absolute basics to mock an API telephone call so you lot can benefit from my 2020 hindsight (heh). If you're going crazy like I was considering you can't effigy out how to just make a simple damn mock, Start here…
(NOTE: The lawmaking below was written in Node.js, only the mocking concepts also apply to frontend Javascript and ES6 modules)
The unmocked lawmaking
We're going to be testing this getFirstAlbumTitle()
function, which fetches an array of albums from an API and returns the title of the first anthology:
// index.js const axios = require ( ' axios ' ); async function getFirstAlbumTitle () { const response = await axios . get ( ' https://jsonplaceholder.typicode.com/albums ' ); render response . data [ 0 ]. title ; } module . exports = getFirstAlbumTitle ;
...and here'due south our initial mock-less test for this part, which verifies the function actually returns the title of the first album in the list:
// alphabetize.test.js const getFirstAlbumTitle = require ( ' ./index ' ); it ( ' returns the title of the first album ' , async () => { const championship = expect getFirstAlbumTitle (); // Run the function expect ( title ). toEqual ( ' quidem molestiae enim ' ); // Brand an assertion on the result });
The test above does its job, but the exam actually makes a network request to an API when information technology runs. This opens the test up to all sorts of false negatives if the API isn't working exactly every bit expected (e.chiliad. the list order changes, API is downward, dev machine loses network connexion, etc.). Not to mention, making these requests in a large number of tests tin bring your test runs to a slow crawl.
Simply how can we change this? The API request is beingness fabricated with axios as a part of getFirstAlbumTitle()
. How in the earth are we supposed to reach inside the function and change the behavior?
Mock it in 3 steps
Alright, hither it is. This is the big hush-hush that would have saved me mountains of fourth dimension as I was wrestling with learning mocks. To mock an API phone call in a role, you only need to exercise these iii steps:
1. Import the module you want to mock into your exam file.
2. jest.mock()
the module.
three. Utilize .mockResolvedValue(<mocked response>)
to mock the response.
That'southward it!
Hither'southward what our test looks like afterward doing this:
// index.test.js const getFirstAlbumTitle = require ( ' ./index ' ); const axios = crave ( ' axios ' ); jest . mock ( ' axios ' ); information technology ( ' returns the title of the kickoff anthology ' , async () => { axios . get . mockResolvedValue ({ data : [ { userId : ane , id : 1 , championship : ' My First Anthology ' }, { userId : i , id : 2 , title : ' Album: The Sequel ' } ] }); const title = await getFirstAlbumTitle (); await ( title ). toEqual ( ' My First Album ' ); });
What's going on here?
Allow'south break this downward. The most important part to sympathize here is the import and jest.mock()
:
const axios = require ( ' axios ' ); jest . mock ( ' axios ' );
When you import a module into a test file, then telephone call it in jest.mock(<module-proper noun>)
, yous take complete control over all functions from that module, even if they're called inside another imported function. Immediately after calling jest.mock('axios')
, Jest replaces every function in the axios module with empty "mock" functions that essentially do nothing and return undefined
:
const axios = require ( ' axios ' ); jest . mock ( ' axios ' ) // Does cipher, so returns undefined: axios . get ( ' https://world wide web.google.com ' ) // Does nothing, then returns undefined: axios . postal service ( ' https://jsonplaceholder.typicode.com/albums ' , { id : 3 , title : ' Album with a Vengeance ' })
So at present that you've eliminated the default beliefs, y'all tin can replace it with your own...
axios . get . mockResolvedValue ({ data : [ { userId : i , id : i , championship : ' My First Album ' }, { userId : 1 , id : 2 , championship : ' Album: The Sequel ' } ] });
The mocked replacement functions that Jest inserted into axios
happen to come with a whole bunch of absurd superpower methods to control their behavior! The most important one here, for the purposes of a simple beginner mock, is .mockResolvedValue()
. When y'all call this on a mocked method, anything you laissez passer in will be the default return value when the mocked function is chosen for the remainder of the test. Just put: you can make axios.get()
return whatever you want! And it doesn't matter whether it'southward called direct in your exam file or as a part of a part imported into your examination – Jest will mock the function no matter where information technology'due south chosen!
Apply this newfound power to give your functions exactly what they should expect from the API calls. Finish worrying about what the network requests render, and merely focus on what YOUR lawmaking does once it gets the response!
If y'all want to play around with the examples, feel free to use this demo repository:
Wrapping up
There y'all have information technology! This is the very nuts of what you need to mock functions from some other module: import the module, jest.mock()
the module, then insert your own return values with .mockResolvedValue()
!
I recommend starting hither, using only these techniques equally yous kickoff building out your kickoff mocks for your network calls. Once you have a foundational understanding of what's going on here, you can slowly start adding the other robust mocking features included in Jest.
See besides: Mocking Modules (Jest documentation).
EDIT: Also, be certain to clear your mocks between tests past running jest.resetAllMocks()
afterward each test. This will assist ensure your mocks won't interfere with future tests. (Thanks for pointing this out, @mjeffe!)
Where to go from here
Alright, yous've learned the basics of mocking and successfully implemented the strategies above in several tests. Y'all tin can import and mock resolved values for all your API calls like an erstwhile pro. What's next?
While the methods described above volition cover most simple use cases, Jest has a lot of mocking functionality and methods to do some really powerful things. You can incrementally add some of the concepts below to super-accuse your mocks:
- Bank check out the other mock part methods listed in the Jest docs: Mock Functions. You tin use methods such equally
mockReturnedValue()
to mock synchronous returns andmockResolvedValueOnce()
to only render a value the kickoff time it's called. - Want to encounter how many times a mocked role is chosen, what it was called with, and what it returned? Bank check out the
mock.calls
andmock.results
backdrop (also in the Mock Functions documentation) - Exercise you lot accept your own custom functions that brand network requests? You can mock your own modules also subsequently they're imported into the examination file:
jest.mock('./path/to/js/module/file')
! Careful here though that you're but mocking what's necessary. Your tests should make certain your functions practice what'due south expected with a given mock input, and it can be easy to end up writing tests that instead only confirm you lot passed in mocked information. - Want a role to human action as it was originally written, only withal want to come across how many times it was called? Check out jest.spyOn().
- Find yourself mocking the same office over and over in multiple tests? Give it default mock responses in
__mocks__
folders using Manual Mocks!
I hope this saves others some of the wasted time and frustration I went through! If anything doesn't make sense here, delight get out a annotate and I'd be happy to attempt to answer any questions. Also, allow me know if in that location's anything else that helped you have an "Aha!" moment while learning to mock!
Source: https://dev.to/zaklaughton/the-only-3-steps-you-need-to-mock-an-api-call-in-jest-39mb
Posted by: connellyhica1947.blogspot.com
0 Response to "How To Mock Service With Ribbonclient Configuration"
Post a Comment