http-vcr-new

Custom VCR matchers for dealing with mutable HTTP-requests

| 2 Comments

VCR is a powerful beast which makes HTTP-request mocking a real no-brainer. If you haven’t tried it before, just do it, it will make your life much easier.

VCR works in really simple manner – when you issue request via some HTTP API, at first it records them and on second request reuse information stored from the first request. The tricky part of such behavior – how to match new request to the one stored before. Usually it just works, but when you have some mutable or random part in an URL it becomes a little bit harder.

In this article you will learn how VCR request-matching works and how to customise matching strategy to deal with mutable URI.

Predefined strategies

VCR has next predefined matchers:

  • :method – HTTP method (i.e. GET, POST, PUT or DELETE) of the request
  • :uri – full URI of the request
  • :host – host of the URI(without port)
  • :path – path of the URI
  • :query – query string values of the URI
  • :body – body of the request(PUT or POST methods)
  • :headers – request headers

You can combine any of these methods to obtain required behavior. By default VCR matches request using :method and :uri. For plane GET request it’s enough.

Strict :uri matching can be substituted with combination of [:host, :path] in case you have some dynamic query part, which doesn’t important for you(e.g. ?timestamp=123). Combination of [:host, :query] can be used if you have dynamic path in URI. But don’t use such combinations, there are much better options, which will be described later.

Matcher for :body is handy for stricter matching of POST/PUT requests, and matcher on :headers when HTTP-headers convey some important data.

Variable query part

The most common case for mutable URI – is some timestamp or another random data in query-part of request. VCR provides special helper for such cases. Use:

Using this helper VCR matches on the whole URI, but excludes :timestamp(and :session) from matching in query-part of URI. Here is an example of usage in RSpec:

Variable path part

Sometimes, especially for REST-API, where you dynamically generate user_id in test and do request to remote server, request path can vary on ID. To skip matching on variable ID, you can write custom URI-matcher. In fact, this way can be used(and should be) when you can’t assemble required matching strategy from standard VCR-matchers.

Custom matcher can be any Proc-object which accepts two VCR::Request objects. Here is an implementation for trailing ID URI:

Notice, we wrote matcher like variable, not like symbol.

Request-object has next API:

  • #method – symbol(:put, :post, etc)
  • #uri – string, full non-parsed URI
  • #body – string, POST/PUT request body
  • #headers – Hash, all request headers
  • #parsed_uri – URI-object(with scheme, host, port, path, and query accessors)

This provides all means to write any custom matching strategy. VCR doesn’t have :port matcher and it can be easily implemented via “parsed_uri”-method:

Variable response

Custom matchers work great if response body isn’t parametrized by request information. If this is a case, you should leverage VCR callbacks and it can be a subject for the whole new article. But there is a good example of such usage at https://github.com/nbibler/vcr-284. It can hint you with required approach.

Anyway, if stuff becomes too complex, it’s much easier to directly use webmock, fakeweb or any other mocking framework which is used by your configuration of VCR.

Move custom matchers into configuration

In case, you want to reuse custom matcher, it can be put in RSpec configuration:

Now you can use :uri_without_timestamp, :port, and :uri_ignoring_trailing_id in tests:

Debug

Sometimes, things go wrong and you need a way to sneak into matching process. Drop this code into any test and it enables debug-mode:

Now you are fully armed and ready to use VCR at its fullest.

Share
* Railsware is a premium software development consulting company, focused on delivering great web and mobile applications. Learn more about us.
  • DmitriyNesteryuk

    Thanks for interesting article. If you use VCR to stub external HTTP requests in Capybara tests, may be you will be interested in my gem https://github.com/nestd/site_prism.vcr.

    • Sergii Boiko

      Nice gem. Will take into account :)

Want to get more of Railsware blog?

RSS FEED

We're always ready to help!

CONTACT US