How to test external API
Using external API as a data source is a common use case in any modern web app. This could be a problem when we start to testing. Any test on the part that use the data source must make request to the actual external API.
App specification
Should be a Rails 3.2 app which has a homepage that display list of recent headlines from ESPN. The homepage need to get the content from the ESPN API.
Here is a typical implementation of above app specification:
- A request for the homepage is route to Headlines controller
- Headlines controller asks Headline model for all recent headlines
- The Headline model gets the latest headlines from the ESPN API
Testing strategy
To test this I'll:
- Start with integration test. I will use RSpec Rails
- Use vcr to record the actual ESPN API HTTP request and response
Start with integration test
Because I don't know the latest headlines on ESPN at the time this spec is run, I only specify an expected DOM structure
#spec/requests/homepage_spec.rb
require 'spec_helper'
describe 'The homepage' do
it 'displays recent headlines from ESPN' do
visit '/'
headlines_links = all '#headlines .item a'
headlines_links.should_not be_empty
headlines_links.each do |link|
link[:href].should match("espn.go.com")
end
end
end
Configure vcr in your spec/spec_helper.rb
require 'vcr' VCR.configure do |config| config.cassette_library_dir = 'spec/cassettes' config.hook_into :fakeweb config.configure_rspec_metadata! end
With the configuration above, when you run the spec, vcr will record the HTTP request to a .yml file in spec/casettes.
Run it again, vcr will replay the response from designated URL where the HTTP request is made.
No real HTTP request are made anymore.
Staying up-to-date
At this point, if the ESPN headlines changes, the specs still continue to pass. We need to keep our recorded "cassette" up-to-date.
Add below line into VCR.configure block in spec/spec_helper.rb.
config.default_cassette_options = {
re_record_interval: 1.week
}
The above tells vcr to re-record all HTTP request and response that are older than 1 week.
Summary
By using vcr to record HTTP request and replay the response, your spec if much faster since no real HTTP request are made after
the first run. Also it made your test more deterministic and accurate.
In this post I focus to show you how to utilize VCR on your spec. There are some missed best-practices here for example you should put the HTTP request implementation in a library instead of model.
You can check out the complete app https://github.com/kiranatama/blog-apps/tree/master/headlines
