DEV Community

Cover image for How to stop API calls in RSpec and Return your Own Data
Robert Hustead
Robert Hustead

Posted on

10 1

How to stop API calls in RSpec and Return your Own Data

tl;dr You can explicitly return whatever data you want from external API requests using Webmock and stubbing requests.

How do you test a Controller that makes an API request to another website, but you want to control what exactly is returned? For example, you want to test a Controller that queries Twitter for tweets, but you don’t want to be at the mercy of whatever tweets are being created that second because you want to test how well you can scrape certain keywords.

That’s where Webmock comes in. https://github.com/bblimke/webmock

By adding the code below to your spec_helper or rails_helper file, you can stub external API requests and control the data that is returned to your controllers.

config.before(:each) do
 stub_request(:get, /some.website.api/).
 with(headers: {‘Accept’: ‘*/*’, ‘User-Agent’: ‘Ruby’ }).
 to_return(status: 200, body:’{“test”: 0}’, headers: {})
end

Lets go through each line:

config.before(:each) do This tells RSpec to run the following code before each spec.

stub_request(:get, /some.website.api/). This is the first part of the stub_request method we get from Webmock. It specifies the type of request (:get -> GET), but you can also use any other RESTful request, including the symbol :any to stub any request that comes in. The second part is the URI. You can use reqex as used above, or strings such as "www.example.com". Basically, this stub_request is now waiting for a GET request to be made to a URI that matches the reqex /some.website.api/

with(header: {'Accept': '*/*', 'User-Agent': 'Ruby' }). In the second part, you can explicitly set the header information you want to match. If in your code you make a GET request to /some.website.api/, but the ‘User-Agent’ is something other than ‘Ruby’, then this stub_request will not be invoked.

to_return(status: 200, body: '{"test": 0}', headers: {}) Finally we reach the line that specifies what response we want when our code calls the API at /some.website.api/. In particular, we can set the status code (Here is 200 which means OK). The body, unsurprisingly, is the data returned to us. In can be one of the following types: [Proc, IO, Pathname, String, Array] . You can also explicitly set the headers of the response.

To Summarize: By using the Webmock gem and the code above in your RSpec helper file, you can stop API requests made by your code and return whatever data you would like.

More info here: https://robots.thoughtbot.com/how-to-stub-external-services-in-tests
Webmock Gem: https://github.com/bblimke/webmock

Happy coding!

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (3)

Collapse
 
epigene profile image
Augusts Bautra

A quick note, often you'll want to return status 200 with a specific body. Since status 200 is to_returns default, you can simply write to_return(body: "something").

Collapse
 
husteadrobert profile image
Robert Hustead

Wow, thanks for the info! The less code you write, the less chance for bugs and errors!

Collapse
 
juliusdelta profile image
JD Gonzales • Edited

Good advice. On smaller projects I tend to do something similar but on my work production application we use the VCR gem which records one call to a yml (a cassette) and then every time the test runs it uses that yml in place of the api response.

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay