It is common for web applications to interface with external services. When testing, since depending on an external service is very fragile, we end up mocking the interaction with such services. However, once in a while, it is still a good idea to check if the contract between your application and the service is still valid.
For example, this week we had to interact with a SOAP service, let’s call it KittenInfo
(why would someone provide kitten information via a SOAP service is beyond the scope of this blog post). We only need to contact one end-point of the KittenInfo
and it is called get_details
, which receives a kitten identifier and returns kitten information:
KittenInfo::Client.new.get_details("gorbypuff")
Since this API is simple, it is very easy to mock the client whenever it is required by our application. On the other hand, we still need to verify that the integration between KittenInfo
SOAP service and our application works correctly, so we write some tests for it:
describe KittenInfo::Client do
it "retrieves kitten details" do
client = KittenInfo::Client.new
details = client.get_details("gorbypuff")
details[:owner].should == "tenderlove"
end
end
However, since this is actually contacting the SOAP Service, it may make your test suite more fragile and slower, even more in this case, in which the SOAP Service responses take as long as kitten’s staring contests.
One possible solution to this problem is to make use of filter tags to exclude the SOAP integration tests from running, except when explicitly desired. We could do this by simply setting:
describe KittenInfo::Client, external: true do
# ...
end
Then, in your spec_helper.rb
, just set:
RSpec.configure do |config|
config.filter_run_excluding external: true
end
Now, running your specs will by default skip all groups that have :external
set to true
. Whenever you tweak the client, or in your builds, you can run those specific tests with:
$ rspec --tag external
Notice that filter mechanism is similar to how we enable JavaScript tests when using Capybara. This means that, when using Capybara, you could also run all JavaScript tests in your app via $ rspec --tag js
or all non-JavaScript tests with $ rspec --tag ~js
.
What about you? What is your favorite RSpec trick?
You can add this flag to automatically convert symbols to hash with true values, so you can create an example like this:
RSpec.configure do |c|
c.treat_symbols_as_metadata_keys_with_true_values = true
end
it “works”, :focus do
should be_nice
end
You can also add a name to your subject:
subject(:serializer) { Serializer.new(foo) }
it “serializes” do
expect(serializer).to be_serializable # this works
should be_serializable # this too!
end
And I really like this “should something” syntax.
Why would you not use something like VCR to store the SOAP response so you don’t have to hit the external service in your tests?
John Beynon, the goal of the tests above is to actually hit the server since once in a while to guarantee the contract between the application and the external service is still valid.
That said VCR is still a good option since it allows you to hit the server by simply cleaning up the cassettes cache and SOAP can be used over HTTP. But depending on the type of external service, you don’t have automatic tools like VCR, so the tip above is still handy.
Thanks for sharing!