golang实现HTTP交互录制与回放的测试插件go-vcr的使用

Golang实现HTTP交互录制与回放的测试插件go-vcr的使用

go-vcr简介

go-vcr通过记录HTTP交互并在未来运行中回放它们,简化测试过程,为代码提供快速、确定性和准确的测试。

安装

执行以下命令安装go-vcr

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

注意:如果从旧版本迁移,可能需要重新创建测试cassette。

基本使用

下面是一个使用go-vcr的简单示例:

package helloworld_test

import (
	"path/filepath"
	"strings"
	"testing"

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

func TestHelloWorld(t *testing.T) {
	// 创建recorder
	r, err := recorder.New(filepath.Join("testdata", strings.ReplaceAll(t.Name(), "/", "_")))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() {
		// 确保完成后停止recorder
		if err := r.Stop(); err != nil {
			t.Error(err)
		}
	})

	client := r.GetDefaultClient()
	url := "https://go.dev/VERSION?m=text"

	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)
}

第一次运行此测试代码将创建testdata/TestHelloWorld.yaml cassette,其中包含HTTP客户端与远程服务器之间的记录交互。

下次执行此测试时,go-vcr将从cassette回放已记录的HTTP交互,而不是进行实际的外部调用。

自定义请求匹配

在回放模式中,可以通过定义recorder.MatcherFunc函数自定义传入请求与记录的请求/响应对的匹配方式。

例如,以下匹配器将匹配方法、URL和正文:

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选项
opts := []recorder.Option{
	recorder.WithMatcher(customMatcher),
}

rec, err := recorder.New("testdata/matchers", opts...)
if err != nil {
        log.Fatal(err)
}
defer rec.Stop() // 确保完成后停止recorder

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

...

Hooks

go-vcr中的hooks是在回放不同阶段调用的常规函数,它们接收HTTP交互。

可以使用hooks在请求/响应保存到磁盘之前修改它们,或在返回给客户端之前修改它们,或者任何其他您可能想做的操作。

以下是移除所有请求中Authorization头的hook示例:

// 移除所有请求中Authorization头的hook
hook := func(i *cassette.Interaction) error {
	delete(i.Request.Headers, "Authorization")
	return nil
}

// Recorder选项
opts := []recorder.Option{
	recorder.WithHook(hook, recorder.AfterCaptureHook),
	recorder.WithMatcher(cassette.NewDefaultMatcher(cassette.WithIgnoreAuthorization())),
}

r, err := recorder.New("testdata/filters", opts...)
if err != nil {
	log.Fatal(err)
}
defer r.Stop() // 确保完成后停止recorder

...

透传请求

有时您希望允许特定请求直接传递到远程服务器而不记录任何内容。

以下是通过特定端点的请求的示例:

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

// Recorder选项
opts := []recorder.Option{
	recorder.WithPassthrough(passthrough),
}

r, err := recorder.New("testdata/filters", opts...)
if err != nil {
	log.Fatal(err)
}
defer r.Stop() // 确保完成后停止recorder

...

服务器端

VCR测试也可用于创建服务器端测试。使用recorder.HTTPMiddleware与HTTP处理程序一起创建来自传入请求和处理程序响应的fixture。然后可以回放这些请求并与记录的响应进行比较以创建回归测试。

许可证

go-vcr是开源的,采用BSD许可证授权。


更多关于golang实现HTTP交互录制与回放的测试插件go-vcr的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现HTTP交互录制与回放的测试插件go-vcr的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用go-vcr实现HTTP交互录制与回放测试

go-vcr是一个优秀的Golang测试库,它可以记录和回放HTTP交互,非常适合用于测试需要与外部API交互的代码。下面我将详细介绍go-vcr的使用方法和示例。

go-vcr的核心概念

go-vcr通过拦截HTTP请求,将第一次请求的真实响应记录下来,后续测试中直接使用记录的响应,从而实现:

  1. 测试不依赖网络连接
  2. 测试运行速度更快
  3. 测试结果可重现
  4. 避免向真实API发送过多请求

安装go-vcr

go get github.com/dnaeon/go-vcr/v3/recorder

基本使用示例

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/dnaeon/go-vcr/v3/recorder"
)

func main() {
	// 启动一个记录器,模式为录制模式
	r, err := recorder.New("fixtures/example")
	if err != nil {
		panic(err)
	}
	defer r.Stop() // 确保记录器停止并保存数据

	// 创建一个使用记录器作为传输的HTTP客户端
	client := &http.Client{
		Transport: r, // 注入我们的记录器
	}

	// 发出HTTP请求
	resp, err := client.Get("https://httpbin.org/get")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(body))
}

测试中使用go-vcr

下面是一个完整的测试示例:

package main

import (
	"net/http"
	"testing"

	"github.com/dnaeon/go-vcr/v3/recorder"
	"github.com/stretchr/testify/assert"
)

func TestHTTPClient(t *testing.T) {
	// 启动记录器,模式为录制模式
	// 第一次运行会创建fixture文件,之后运行会使用它
	r, err := recorder.New("fixtures/httpbin")
	if err != nil {
		t.Fatal(err)
	}
	defer r.Stop()

	// 创建使用记录器的HTTP客户端
	client := &http.Client{
		Transport: r,
	}

	// 执行请求
	resp, err := client.Get("https://httpbin.org/get")
	if err != nil {
		t.Fatalf("Failed to make request: %v", err)
	}
	defer resp.Body.Close()

	// 验证响应
	assert.Equal(t, http.StatusOK, resp.StatusCode)
	assert.Equal(t, "application/json", resp.Header.Get("Content-Type"))
}

记录器模式

go-vcr有几种工作模式:

// 模式设置示例
r, err := recorder.New("fixtures/example")
if err != nil {
    panic(err)
}

// 设置模式
r.SetMode(recorder.ModeRecordOnce) // 只录制一次,之后回放
// r.SetMode(recorder.ModeReplayOnly) // 只回放,不录制
// r.SetMode(recorder.ModePassthrough) // 直接传递请求,不录制
// r.SetMode(recorder.ModeDisabled) // 完全禁用

高级功能

1. 过滤敏感信息

r, err := recorder.New("fixtures/example")
if err != nil {
    panic(err)
}

// 添加过滤器来移除敏感信息
r.AddFilter(func(i *cassette.Interaction) error {
    delete(i.Request.Headers, "Authorization")
    return nil
})

2. 自定义匹配器

默认情况下,go-vcr根据方法、URL和正文匹配请求。你可以自定义匹配逻辑:

r, err := recorder.New("fixtures/example")
if err != nil {
    panic(err)
}

// 添加自定义匹配器
r.AddMatcher(func(r *http.Request, i cassette.Request) bool {
    return r.URL.Path == i.URL
})

3. 禁用压缩

有些API返回压缩的响应,你可能想禁用压缩以便更容易检查fixture文件:

r, err := recorder.New("fixtures/example")
if err != nil {
    panic(err)
}

r.DisableCompression = true

实际测试示例

func TestGitHubAPI(t *testing.T) {
    // 设置记录器
    r, err := recorder.New("fixtures/github")
    if err != nil {
        t.Fatal(err)
    }
    defer r.Stop()
    
    // 设置模式为录制一次
    r.SetMode(recorder.ModeRecordOnce)
    
    // 创建客户端
    client := github.NewClient(&http.Client{Transport: r})
    
    // 调用API
    repos, _, err := client.Repositories.List(context.Background(), "octocat", nil)
    if err != nil {
        t.Fatalf("Failed to get repositories: %v", err)
    }
    
    // 验证结果
    if len(repos) == 0 {
        t.Error("Expected some repositories, got none")
    }
}

最佳实践

  1. 将fixture文件(.yml)加入版本控制
  2. 为不同的测试用例使用不同的fixture文件
  3. 定期更新fixture文件以确保它们不过时
  4. 在CI环境中使用ModeReplayOnly模式
  5. 过滤掉敏感信息如API密钥、认证令牌等

go-vcr是一个强大的工具,可以显著提高依赖外部HTTP服务的测试的可靠性和速度。通过合理使用,你可以创建既快速又可靠的测试套件。

回到顶部