I'm developing a DSL for building API wrappers, named Hendrix. I am having problems with the testing of the DSL. As it is a API wrapper, it needs to interact with external services. I am not sure how to approach this in terms of testing. I'm using RSpec and tried configuring VCR with WebMock, but no luck. How am I supposed to test this particular scenario if I don't have direct access to what request is being made?
This is my spec_helper.rb
:
$VERBOSE = nil
require 'simplecov'
require 'coveralls'
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
SimpleCov::Formatter::HTMLFormatter,
Coveralls::SimpleCov::Formatter
]
SimpleCov.start { add_filter '/spec/' }
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'hendrix'
require 'vcr'
VCR.configure do |c|
c.cassette_library_dir = 'spec/cassettes'
c.hook_into :webmock
end
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true
config.filter_run :focus
config.order = 'random'
config.extend VCR::RSpec::Macros
end
The project is in its early stages (working towards version 0.1.0 at the moment). The syntax of the DSL is as follows:
require 'hendrix'
Hendrix.build 'Jimi' do
base 'https://api.github.com'
client :issues do
action :issue, '/repos/:owner/:repo/issues/:number'
end
end
Jimi.issue('rafalchmiel', 'hendrix', 1)
# => {"url"=>"https://api.github.com/repos/rafalchmiel/hendrix/issues/1",
# "labels_url"=> ...
Jimi.issue('rafalchmiel', 'hendrix', 1).title
# => "Implement parameters in actions"
In most specs, I'm testing what the methods from the master module (in this case Jimi.issue
etc) return and whether it is in a Hashie::Mash
format. How would I test this? I don't know where to start.
For integration tests, I usually stub the endpoint with webmock directly, without trying to record an actual request. This means you can control the response and the expectation in the same place. You can place expectations on whether your library parses the response correctly and you can write tests that verify that the request has been made correctly. Go through each of the features of your gem to get a list of features. Here's an example:
require "webmock/rspec"
describe "parsing results" do
let(:url) { "http://..." }
it "parses results into nice methods" do
stub_request(:get, url)
.to_return(
body: { title: "implement" }.to_json,
headers: { content_type: "application/json" },
)
perform_request
expect(response.title).to eq "implement"
end
it "sends the user agent header correctly" do
stub_request(:get, url)
perform_request
expect(a_request(:get, url).with(
headers: { user_agent: "hendrix" }
)).to have_been_made.once
end
it "interpolates values in URLs"
it "supports DELETE requests"
it "supports HTTP Basic"
def perform_request
# ...
end
end
Try not to record real requests: it's hard to control the right circumstances with real web servers, especially if you're not the one who wrote the specs. Especially when you write a general purpose library like this. VCR is nice if you want to access one particular server and your code really depends on that one server.
Also don't check on types. I see that quite a lot in your gem right now. Nobody cares if you return a Hashie::Mash object. As my first spec shows, you just want to be able to access the attributes cleanly.