Convert Figma logo to code with AI

dnaeon logogo-vcr

Record and replay your HTTP interactions for fast, deterministic and accurate tests

1,231
75
1,231
1

Top Related Projects

5,817

Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.

10,203

Record, Replay, and Stub HTTP Interactions.

12,673

HTTP server mocking and expectations library for Node.js

Quick Overview

go-vcr is a Go library that provides HTTP interaction recording and playback functionality, similar to the VCR gem in Ruby. It allows developers to record HTTP interactions during tests and play them back in subsequent test runs, improving test reliability and speed.

Pros

  • Speeds up test execution by eliminating network calls in subsequent runs
  • Improves test reliability by removing dependencies on external services
  • Supports custom matchers for flexible request matching
  • Compatible with Go's standard http.Client and can be easily integrated into existing codebases

Cons

  • Recorded cassettes may become outdated if the external API changes
  • May not accurately represent real-world scenarios if used excessively
  • Requires careful management of cassettes to avoid committing sensitive information
  • Limited support for streaming responses

Code Examples

Recording a new cassette:

r, err := recorder.New("fixtures/example")
if err != nil {
    log.Fatal(err)
}
defer r.Stop()

client := &http.Client{
    Transport: r,
}

resp, err := client.Get("http://example.com")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

Using a custom matcher:

r, _ := recorder.New("fixtures/custom_matcher")
r.SetMatcher(func(r *http.Request, i cassette.Request) bool {
    return r.Method == i.Method && r.URL.Path == i.URL
})

Filtering sensitive information:

r, _ := recorder.New("fixtures/filtered")
r.AddFilter(func(i *cassette.Interaction) error {
    delete(i.Request.Headers, "Authorization")
    return nil
})

Getting Started

To use go-vcr in your project:

  1. Install the library:

    go get github.com/dnaeon/go-vcr/recorder
    
  2. Import and use in your code:

    import (
        "github.com/dnaeon/go-vcr/recorder"
        "net/http"
    )
    
    func main() {
        r, _ := recorder.New("fixtures/my_cassette")
        defer r.Stop()
    
        client := &http.Client{
            Transport: r,
        }
    
        // Use the client to make HTTP requests
        // They will be recorded or played back
    }
    

Competitor Comparisons

5,817

Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.

Pros of vcr

  • More mature and widely used in the Ruby ecosystem
  • Extensive documentation and community support
  • Supports multiple HTTP libraries and adapters

Cons of vcr

  • Limited to Ruby language and ecosystem
  • May require more setup and configuration for complex scenarios

Code Comparison

vcr:

VCR.use_cassette("example") do
  response = Net::HTTP.get_response(URI('http://example.com'))
end

go-vcr:

recorder, err := vcr.New("fixtures/example")
defer recorder.Stop()

client := &http.Client{Transport: recorder}
resp, err := client.Get("http://example.com")

Key Differences

  • Language: vcr is for Ruby, while go-vcr is for Go
  • Integration: vcr integrates with various Ruby HTTP libraries, while go-vcr focuses on Go's net/http package
  • Flexibility: vcr offers more configuration options and matchers, while go-vcr provides a simpler API

Use Cases

  • vcr: Ideal for Ruby projects with complex HTTP interactions and testing requirements
  • go-vcr: Well-suited for Go projects needing straightforward HTTP request recording and playback

Both libraries serve similar purposes in their respective ecosystems, offering developers tools to record and replay HTTP interactions for testing and development purposes.

10,203

Record, Replay, and Stub HTTP Interactions.

Pros of Pollyjs

  • Cross-platform support (Node.js and browser)
  • More extensive features, including request matching and response customization
  • Active development and maintenance by Netflix

Cons of Pollyjs

  • Larger codebase and potentially steeper learning curve
  • JavaScript-specific, limiting use in other language ecosystems

Code Comparison

go-vcr:

r, err := recorder.New("fixtures/example")
defer r.Stop()

client := &http.Client{
    Transport: r,
}

Pollyjs:

const polly = new Polly('example');
const { server } = polly;

server.get('/api').intercept((req, res) => {
  res.status(200).json({ message: 'Hello World' });
});

Key Differences

  • Language: go-vcr is written in Go, while Pollyjs is JavaScript-based
  • Scope: go-vcr focuses on HTTP recording/playback, Pollyjs offers broader functionality
  • Configuration: Pollyjs provides more granular control over request matching and response handling
  • Ecosystem: go-vcr integrates well with Go testing frameworks, Pollyjs with JavaScript testing tools

Both libraries serve similar purposes but cater to different language ecosystems and offer varying levels of complexity and features. The choice between them largely depends on the project's language, requirements, and desired level of control over the recording and playback process.

12,673

HTTP server mocking and expectations library for Node.js

Pros of nock

  • Widely adopted in the JavaScript ecosystem with extensive community support
  • Offers powerful request matching capabilities, including regex and function-based matchers
  • Provides built-in support for common HTTP scenarios like persistent mocks and delayed responses

Cons of nock

  • Limited to Node.js environment, not suitable for browser-based applications
  • Can be more complex to set up and maintain for large test suites
  • Mocking at the HTTP level may not capture all nuances of real network interactions

Code Comparison

nock:

const nock = require('nock');
const scope = nock('https://api.example.com')
  .get('/users')
  .reply(200, { users: ['Alice', 'Bob'] });

go-vcr:

r, err := recorder.New("fixtures/users")
defer r.Stop()

client := &http.Client{Transport: r}
resp, err := client.Get("https://api.example.com/users")

Key Differences

  • Language: nock is for JavaScript/Node.js, while go-vcr is for Go
  • Approach: nock intercepts HTTP requests at runtime, go-vcr records and replays HTTP interactions
  • Flexibility: nock offers more fine-grained control over mocked responses, while go-vcr focuses on simplicity and real response playback

Both libraries serve similar purposes but cater to different ecosystems and testing philosophies. nock is more suitable for detailed mocking scenarios, while go-vcr excels in recording and replaying actual HTTP interactions.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

go-vcr

Build Status Go Reference Go Report Card codecov

go-vcr simplifies testing by recording your HTTP interactions and replaying them in future runs in order to provide fast, deterministic and accurate testing of your code.

go-vcr was inspired by the VCR library for Ruby.

Installation

Install go-vcr by executing the command below:

$ go get -v gopkg.in/dnaeon/go-vcr.v4

Note, that if you are migrating from a previous version of go-vcr, you may need to re-create your tests cassettes.

Usage

A quick example of using go-vcr.

package helloworld_test

import (
	"testing"

	"gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
)

func TestHelloWorld(t *testing.T) {
	// Create our recorder
	r, err := recorder.New("fixtures/hello-world")
	if err != nil {
		t.Fatal(err)
	}
	defer r.Stop() // Make sure recorder is stopped once done with it

	client := r.GetDefaultClient()
	url := "https://go.dev/"

	resp, err := client.Get(url)
	if err != nil {
		t.Fatalf("Failed to get url %s: %s", url, err)
	}

	t.Logf("GET %s: %d\n", url, resp.StatusCode)
}

Running this test code for the first time will result in creating the fixtures/hello-world.yaml cassette, which will contain the recorded HTTP interaction between our HTTP client and the remote server.

When we execute this test next time, what would happen is that go-vcr will replay the already recorded HTTP interactions from the cassette, instead of making actual external calls.

Please also check the examples directory from this repo for complete and ready to run examples.

You can also refer to the test cases for additional examples.

Custom Request Matching

During replay mode, you can customize the way incoming requests are matched against the recorded request/response pairs by defining a recorder.MatcherFunc function.

For example, the following matcher will match on method, URL and body:


func customMatcher(r *http.Request, i cassette.Request) bool {
	if r.Body == nil || r.Body == http.NoBody {
		return cassette.DefaultMatcher(r, i)
	}

	var reqBody []byte
	var err error
	reqBody, err = io.ReadAll(r.Body)
	if err != nil {
		log.Fatal("failed to read request body")
	}
	r.Body.Close()
	r.Body = ioutil.NopCloser(bytes.NewBuffer(reqBody))

	return r.Method == i.Method && r.URL.String() == i.URL && string(reqBody) == i.Body
}

...

// Recorder options
opts := []recorder.Option{
	recorder.WithCassette("fixtures/matchers"),
	recorder.WithMatcher(customMatcher),
}

rec, err := recorder.New(opts...)
if err != nil {
        log.Fatal(err)
}
defer rec.Stop() // Make sure recorder is stopped once done with it

client := rec.GetDefaultClient()
resp, err := client.Get("https://www.google.com/")

...

Hooks

Hooks in go-vcr are regular functions which take an HTTP interaction and are invoked at different stages of the playback.

You can use hooks to modify a request/response before it is saved on disk, before it is returned to the client, or anything else that you might want to do with it, e.g. you might want to simply log each captured interaction.

You often provide sensitive data, such as API credentials, when making requests against a service.

By default, this data will be stored in the recorded data but you probably don't want this.

Removing or replacing data before it is stored can be done by adding one or more Hooks to your Recorder.

There are different kinds of hooks, which are invoked in different stages of the playback. The supported hook kinds are AfterCaptureHook, BeforeSaveHook, BeforeResponseReplayHook and OnRecorderStop.

Here is an example that removes the Authorization header from all requests right after capturing a new interaction.

// A hook which removes Authorization headers from all requests
hook := func(i *cassette.Interaction) error {
	delete(i.Request.Headers, "Authorization")
	return nil
}

// Recorder options
opts := []recorder.Option{
	recorder.WithCassette("fixtures/filters"),
	recorder.WithHook(hook, recorder.AfterCaptureHook),
	recorder.WithMatcher(cassette.NewDefaultMatcher(cassette.WithIgnoreAuthorization(true))),
}

r, err := recorder.New(opts...)
if err != nil {
	log.Fatal(err)
}
defer r.Stop() // Make sure recorder is stopped once done with it

...

Hooks added using recorder.AfterCaptureHook are applied right after an interaction is captured and added to the in-memory cassette. This may not always be what you need. For example if you modify an interaction using this hook kind then subsequent test code will see the edited response.

For instance, if a response body contains an OAuth access token that is needed for subsequent requests, then redacting the access token using a AfterCaptureHook will result in authorization failures in subsequent test code.

In such cases you would want to modify the recorded interactions right before they are saved on disk. For that purpose you should be using a BeforeSaveHook, e.g.

// Your test code will continue to see the real access token and
// it is redacted before the recorded interactions are saved on disk
hook := func(i *cassette.Interaction) error {
	if strings.Contains(i.Request.URL, "/oauth/token") {
		i.Response.Body = `{"access_token": "[REDACTED]"}`
	}

	return nil
}

// Recorder options
opts := []recorder.Option{
	recorder.WithCassette("fixtures/filters"),
	recorder.WithHook(hook, recorder.BeforeSaveHook),
}

r, err := recorder.New(opts...)
if err != nil {
	log.Fatal(err)
}
defer r.Stop() // Make sure recorder is stopped once done with it

...

Passing Through Requests

Sometimes you want to allow specific requests to pass through to the remote server without recording anything.

Globally, you can use ModePassthrough for this, but if you want to disable the recorder for individual requests, you can add Passthrough handlers to the recorder.

Here's an example to pass through requests to a specific endpoint:

passthrough := func(req *http.Request) bool {
	return req.URL.Path == "/login"
}

// Recorder options
opts := []recorder.Option{
	recorder.WithCassette("fixtures/filters"),
	recorder.WithPassthrough(passthrough),
}

r, err := recorder.New(opts...)
if err != nil {
	log.Fatal(err)
}
defer r.Stop() // Make sure recorder is stopped once done with it

...

Server Side

VCR testing can also be used for creating server-side tests. Use the recorder.HTTPMiddleware with an HTTP handler in order to create fixtures from incoming requests and the handler's responses. Then, these requests can be replayed and compared against the recorded responses to create a regression test.

Rather than mocking/recording external HTTP interactions, this will record and replay incoming interactions with your application's HTTP server.

See an example here.

License

go-vcr is Open Source and licensed under the BSD License