Fast Remote Service Tests

February 25th, 2014

Testing code that interacts with remote services is often pretty hard. There are a lot of tradeoffs that influence what tests you can write and the amount of tests to write. Most of the times you have zero control over the data you get from the service, which makes assertions tough to say the least.

A while ago I used the VCR library to write some Ruby tests against a remote service. VCR addresses the above problems. It records your test suite’s HTTP interactions to replay them during future runs. The obvious benefits are fast and repeatable tests.

This week I was wondering whether that’s a thing for Java as well. As it turns out there’s Betamax to do that. Actually Betamax is a Groovy port of VCR that can be used with any JVM language.

Betamax installs a proxy in between you and the target host, records each request and response on tape and replays the tape for known requests. It works for any HTTP client that respects Java’s proxy settings, and for a bunch that don’t such as Apache HttpClient and WSLite.

Example

In a JUnit test you can use Betamax as a method-level TestRule. On each test-method that should record and replay you put an @Betamax recorder and set a tape.

Consider the following example where I use the Spotify Metadata API to get the popularity of an artist. In this example I use the Apache HttpClient library and configure it for Betamax.

public class SpotifyTest {
  @Rule public final Recorder recorder = new Recorder();

  private final DefaultHttpClient http = new DefaultHttpClient();

  @Betamax(tape = "fixtures/popularity")
  @Test
  public void get_popularity() throws Exception {
    Spotify spotify = new Spotify(http);
    assertThat(spotify.popularity("The Beatles"), is(.55f));
  }

  @Before
  public void setUp() throws Exception {
    BetamaxRoutePlanner.configure(http);
  }
}

At the moment of writing this code the popularity of The Beatles is .55 but as this number is based on user opinion it is highly likely to change. Using a Betamax tape gets the same response (as long as the request does not change) and allows to assert .55 for popularity.

HTTPS

As I’ve shown you Betamax properly records and replays any HTTP communication using either a proxy or a wrapper class (as in the example). HTTPS is also supported but may be a bit more interesting as you use Betamax in a proxy-based setup. Using a wrapper will work just fine.

The problem with HTTPS and a proxy-based setup obviously is that the proxy cannot intercept data on standard HTTPS communication. This is why we trust HTTPS.

Betamax has its way around this. You can enable sslSupport on the Betamax Recorder. When your client code is okay with a broken SSL certificate chain you can make this work.

Again this is only really a problem as you use a proxy-based setup. Using a client wrapper enables Betamax directly on API calls easing HTTPS communication.

Try it yourself

Betamax can help you to write fast and repeatable unit tests for clients of remote services. The most beneficial to me is that the tests are really fast because remote communication is eliminated. Asserting on specific values can be helpful although personally I like a property-based style for these tests (e.g. popularity must be a number >= 0 and <= 5).

Give Betamax a try the next time you interact with a remote service.