Writing Faster HTTP Tests in Ruby on Rails with VCR

Daniel Pericich
4 min readMar 6, 2023

--

Photo by Jakob Owens on Unsplash

The tests take way too long to run. You’re trying to push a small fix up to Github and your automated test suite runs and runs and runs. 15 minutes later you are still waiting to see if you can be done with work for the night, or if you’ll have another 20 minutes of automated tests to get through if your fix doesn’t take. There has to be a quicker way to run automated tests.

Having instant test results is impossible, especially when your code base reaches a certain size. However, there are ways that you can structure your tests to avoid unnecessary loading and waiting for test assets. Let’s take a look at how we can record HTTP calls to write faster tests in RSpec.

Issues with Testing External API Calls

If your web app or service reaches a certain complexity, you will probably be calling external services to get and sync data. Writing tests for these operations is very important as ensuring external calls work is a lot more difficult than fail-proofing internal calls.

Once you’ve written your code, you need to have tests that cover edge cases and scenarios for how the service would respond. Along with a successful call, we may need to handle responses for missing resources, malformed requests, and server outages. Each of these requires more HTTP test calls and may include child calls. All of these tests can potentially lead to dozens of HTTP calls. This is a problem.

The two main issues we see with making lots of live calls in our test suites are speed and repeatability. Speed is straightforward as for each call we need to form a request, send it to the service, wait for them to complete some business logic, form a response and return the response. This could take milliseconds up to a few seconds. If we are making dozens of calls that take a few seconds each new service could add minutes of tests to our suite. Adding minutes is a worst-case scenario for use.

The other issue with making live HTTP calls in our test suites is that they are not repeatable. What this means is that a call relies on many factors including network conditions, server traffic, and even server reliability. Our calls may be good, but our tests may fail due to conditions outside of our control. Remember, testing is meant to show a specific functionality works, not prove that a service has amazing uptime.

Both of these issues can cause us a lot of issues from having long test times to flaky tests that require multiple runs. How can we fix this?

Stubbing HTTP Requests

We need to be able to write our tests against real external responses, but that doesn’t mean that we need a new response every time we run a test. Instead, we can stub the test by running our method against the service and recording the response. As long as the service is stable, we can expect the same response to our request every time and thus can reuse the recorded response going forward.

This saves us from our two issues as we won’t add the actual HTTP method call time to our automated test suite and we already have our response so we don’t have to worry about unreliable services.

Manually recording the response to our method call can be tedious, but there are plenty of gems and packages that will automate the process of recording HTTP calls, creating yaml files, and then calling the files when we rerun the tests. These packages couldn’t make writing fast, reliable, and well-documented external service call tests any easier!

Using VCR with RSpec to Create Stubbed Calls

Professionally, I work a lot in Ruby on Rails. The test framework I use is RSpec, and the first gem I reach for when I am writing a client or service module for an external HTTP service is VCR. VCR is a blast from the past as it is a gem that allows users to wrap their assertions in cassettes, or yaml response file calls, and run the tests against this response instead of making the call. Of course, VCR does make the call one time which it uses to create the response. VCR then leverages this yaml response file for testing after it has been generated.

Here is what a basic VCR test setup would look like:

Figure 1. Example of VCR setup for HTTP call from the VCR Github repo README.

While this setup is basic, it will help you handle most cases of HTTP method tests you may have. If you need modifications to hide sensitive data then check out the VCR Github docs page which is linked in the notes.

Conclusion

Tests have two important roles when it comes to furthering software. First, they act as a way to prove that code works and continues to work as expected when other features or services are introduced to a codebase. Second, they serve as human-readable documentation of how the software should work. They should be readable, fast, and reliable. I hope that this article helps you write tests, specifically HTTP method calls, that are fast and reliable.

Notes

https://github.com/vcr/vcr

--

--

Daniel Pericich
Daniel Pericich

Written by Daniel Pericich

Former Big Beer Engineer turned Full Stack Software Engineer

No responses yet