Skip to content

Repository files navigation

EasyVCR

CIcodecovMaven Central

EasyVCR is a library for recording and replaying HTTP interactions in your test suite.

This can be useful for speeding up your test suite, or for running your tests on a CI server which doesn't have connectivity to the HTTP endpoints you need to interact with.

Install

Maven

Add this to your project's POM:

<dependency>
<groupId>com.easypost</groupId>
<artifactId>easyvcr</artifactId>
<version>0.5.3</version>
</dependency>

Gradle

Add this to your project's build file:

implementation "com.easypost:easyvcr:0.5.3"

Supported HTTP Clients

How to use EasyVCR

Step 1

Run your test suite locally against a real HTTP endpoint in recording mode

importcom.easypost.easyvcr;
importcom.easypost.easyvcr.Cassette;
importcom.easypost.easyvcr.Mode;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
publicclassExample {
publicstaticvoidmain(String[] args) {
// Create a cassette to handle HTTP interactionsCassettecassette = newCassette("path/to/cassettes", "my_cassette");
// create a RecordableURL using the cassetteRecordableURLrecordableURL = newRecordableURL("https://www.example.com", cassette, Mode.Record);
// open the connection to get a Http(s)URLConnectionRecordableHttpsURLConnectionconnection = recordableURL.openConnectionSecure();
// A RecordableHttp(s)URLConnection extends a normal Http(s)URLConnection, so you can use it as you would a normal Http(s)URLConnectionconnection.setConnectTimeout(1000);
connection.connect();
intresponseCode = connection.getResponseCode();
}
}

Real HTTP calls will be made and recorded to the cassette file.

Step 2

Switch to replay mode:

importcom.easypost.easyvcr;
importcom.easypost.easyvcr.Cassette;
importcom.easypost.easyvcr.Mode;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
publicclassExample {
publicstaticvoidmain(String[] args) {
// Create a cassette to handle HTTP interactionsCassettecassette = newCassette("path/to/cassettes", "my_cassette");
// create a RecordableURL using the cassetteRecordableURLrecordableURL = newRecordableURL("https://www.example.com", cassette, Mode.Replay);
// open the connection to get a Http(s)URLConnectionRecordableHttpsURLConnectionconnection = recordableURL.openConnectionSecure();
// A RecordableHttp(s)URLConnection extends a normal Http(s)URLConnection, so you can use it as you would a normal Http(s)URLConnectionintresponseCode = connection.getResponseCode();
}
}

Now when tests are run, no real HTTP calls will be made. Instead, the HTTP responses will be replayed from the cassette file.

Available modes

  • Mode.Auto: Play back a request if it has been recorded before, or record a new one if not. (default mode for VCR)
  • Mode.Record: Record a request, including overwriting any existing matching recording.
  • Mode.Replay: Replay a request. Throws an exception if no matching recording is found.
  • Mode.Bypass: Do not record or replay any requests (client will behave like a normal HttpClient).

Features

EasyVCR comes with a number of features, many of which can be customized via the AdvancedOptions class.

Censoring

Censor sensitive data in the request and response, such as API keys and auth tokens.

Can censor:

  • Request and response headers (via key name)
  • Request and response bodies (via key name) (JSON only)
  • Request query parameters (via key name)
  • Request URL path elements (via regex pattern matching)

Default: Disabled

importcom.easypost.easyvcr;
importcom.easypost.easyvcr.AdvancedSettings;
importcom.easypost.easyvcr.Cassette;
importcom.easypost.easyvcr.CensorElement;
importcom.easypost.easyvcr.Censors;
importcom.easypost.easyvcr.Mode;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
importjava.util.ArrayList;
publicclassExample {
publicstaticvoidmain(String[] args) {
Cassettecassette = newCassette("path/to/cassettes", "my_cassette");
AdvancedSettingsadvancedSettings = newAdvancedSettings();
List<String> headersToCensor = newArrayList<>();
headersToCensor.add("Authorization"); // Hide the Authorization headeradvancedSettings.censors = newCensors().censorHeadersByKeys(headersToCensor);
advancedSettings.censors.censorBodyElements(newArrayList<>() {{
add(newCensorElement("table", true)); // Hide the table element (case-sensitive) in the request and response body
}});
advancedSettings.censors.censorPathElementsByPattern(newArrayList<>() {{
add(".*\\d{4}.*"); // Hide any path element that contains 4 digits
}});
// oradvancedSettings.censors =
Censors.strict(); // use the built-in strict censoring mode (hides common sensitive data)RecordableURLrecordableURL =
newRecordableURL("https://www.example.com", cassette, Mode.Replay, advancedSettings);
RecordableHttpsURLConnectionconnection = recordableURL.openConnectionSecure();
}
}

Delay

Simulate a delay when replaying a recorded request, either using a specified delay or the original request duration.

Default: No delay

importcom.easypost.easyvcr;
importcom.easypost.easyvcr.AdvancedSettings;
importcom.easypost.easyvcr.Cassette;
importcom.easypost.easyvcr.Mode;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
publicclassExample {
publicstaticvoidmain(String[] args) {
Cassettecassette = newCassette("path/to/cassettes", "my_cassette");
AdvancedSettingsadvancedSettings = newAdvancedSettings();
advancedSettings.manualDelay = 1000; // Simulate a delay of 1000 milliseconds when replayingadvancedSettings.simulateDelay = true; // Simulate a delay of the original request duration when replaying (overrides manualDelay)RecordableURLrecordableURL = newRecordableURL("https://www.example.com", cassette, Mode.Replay, advancedSettings);
RecordableHttpsURLConnectionconnection = recordableURL.openConnectionSecure();
}
}

Expiration

Set expiration dates for recorded requests, and decide what to do with expired recordings.

Default: No expiration

importcom.easypost.easyvcr;
importcom.easypost.easyvcr.AdvancedSettings;
importcom.easypost.easyvcr.Cassette;
importcom.easypost.easyvcr.ExpirationActions;
importcom.easypost.easyvcr.Mode;
importcom.easypost.easyvcr.TimeFrame;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
publicclassExample {
publicstaticvoidmain(String[] args) {
Cassettecassette = newCassette("path/to/cassettes", "my_cassette");
AdvancedSettingsadvancedSettings = newAdvancedSettings();
advancedSettings.timeFrame = newTimeFrame(30, 0, 0, 0); // Any matching request is considered expired if it was recorded more than 30 days ago// oradvancedSettings.timeFrame =
TimeFrame.months12(); // Any matching request is considered expired if it was recorded more than a year agoadvancedSettings.whenExpired = ExpirationActions.ThrowException; // Throw exception if the recording is expiredRecordableURLrecordableURL =
newRecordableURL("https://www.example.com", cassette, Mode.Replay, advancedSettings);
RecordableHttpsURLConnectionconnection = recordableURL.openConnectionSecure();
}
}

Matching

Customize how a recorded request is determined to be a match to the current request.

Default: Method and full URL must match

importcom.easypost.easyvcr;
importcom.easypost.easyvcr.AdvancedSettings;
importcom.easypost.easyvcr.Cassette;
importcom.easypost.easyvcr.MatchRules;
importcom.easypost.easyvcr.Mode;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
publicclassExample {
publicstaticvoidmain(String[] args) {
Cassettecassette = newCassette("path/to/cassettes", "my_cassette");
AdvancedSettingsadvancedSettings = newAdvancedSettings();
advancedSettings.matchRules = newMatchRules().byBody().byHeader("X-My-Header"); // Match recorded requests by request body (i.e. POST data) and a specific header// oradvancedSettings.matchRules = MatchRules.strict(); // use the built-in strict matching mode (matches by method, full URL and request body; useful for POST/PATCH/PUT requests)RecordableURLrecordableURL =
newRecordableURL("https://www.example.com", cassette, Mode.Replay, advancedSettings);
RecordableHttpsURLConnectionconnection = recordableURL.openConnectionSecure();
}
}

Logging

Have EasyVCR integrate with your custom logger to log warnings and errors.

Default: Logs to console

importcom.easypost.easyvcr;
importcom.easypost.easyvcr.AdvancedSettings;
importcom.easypost.easyvcr.Cassette;
importcom.easypost.easyvcr.MatchRules;
importcom.easypost.easyvcr.Mode;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
publicclassExample {
publicstaticvoidmain(String[] args) {
Cassettecassette = newCassette("path/to/cassettes", "my_cassette");
AdvancedSettingsadvancedSettings = newAdvancedSettings();
advancedSettings.logger = newMyCustomLogger(); // Have EasyVCR use your custom logger when making log entriesRecordableURLrecordableURL =
newRecordableURL("https://www.example.com", cassette, Mode.Replay, advancedSettings);
RecordableHttpsURLConnectionconnection = recordableURL.openConnectionSecure();
}
}

VCR

In addition to individual recordable HttpClient instances, EasyVCR also offers a built-in VCR, which can be used to easily switch between multiple cassettes and/or modes. Any advanced settings applied to the VCR will be applied on every request made using the VCR's HTTP client.

importcom.easypost.easyvcr;
importcom.easypost.easyvcr.AdvancedSettings;
importcom.easypost.easyvcr.Cassette;
importcom.easypost.easyvcr.Censors;
importcom.easypost.easyvcr.Mode;
importcom.easypost.easyvcr.VCR;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
importcom.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
publicclassExample {
publicstaticvoidmain(String[] args) {
AdvancedSettingsadvancedSettings = newAdvancedSettings();
List<String> censoredQueryParams = newArrayList<String>();
censoredQueryParams.add("api_key"); // hide the api_key query parameteradvancedSettings.censors = newCensors().hideQueryParameter(censoredQueryParams);
// Create a VCR with the advanced settings appliedVCRvcr = newVCR(advancedSettings);
// Create a cassette and add it to the VCRCassettecassette = newCassette("path/to/cassettes", "my_cassette");
vcr.insert(cassette);
// Set the VCR to record modevcr.record();
// Get a RecordableURL instance from the VCRRecordableURLrecordableURL = vcr.getHttpUrlConnection("https://www.example.com");
// Use the client as you would normally.RecordableHttpsURLConnectionconnection = recordableURL.openConnectionSecure();
connection.connect();
// Remove the cassette from the VCR vcr.eject();
}
}

Development

Tests

# Build project
just install
# Run tests
just build test# Run tests with coverage
just coverage

Testing

The test suite in this project was specifically built to produce consistent results on every run, regardless of when they run or who is running them.

The cassettes used in the test suite are stored in a "cassettes" directory in the project root. Most of the cassettes produced by the test suite are erased and recreated on each run. Nevertheless, the test suite may complain if the cassettes are not present, so please do not delete them manually.

Credit

About

EasyVCR is a Java library for recording and replaying HTTP interactions, packed with advanced features to customize your testing experience. Based on the EasyVCR .NET library.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

10 stars

Watchers

31 watching

Forks

Releases

Packages

Used by

Contributors

Languages