golang实现HTTP请求录制与回放的离线测试插件库govcr的使用

Golang实现HTTP请求录制与回放的离线测试插件库govcr的使用

govcr是一个用于记录和回放HTTP/HTTPS交互的Go库,主要用于离线单元测试、行为测试和集成测试,也可以用于API模拟。

简单示例

// 完整示例请参考测试中的TestExample1
func TestExample1() {
    vcr := govcr.NewVCR(
        govcr.NewCassetteLoader("MyCassette1.json"),
        govcr.WithRequestMatchers(govcr.NewMethodURLRequestMatchers()...), // 使用"宽松"的请求匹配器
    )

    vcr.Client.Get("http://example.com/foo")
}

第一次运行此示例时,MyCassette1.json文件不存在,TestExample1会进行真实的HTTP调用。

在后续执行中(除非删除cassette文件),HTTP调用将从cassette回放,不会发生真实的HTTP调用。

注意:我们使用"宽松"的请求匹配器是因为example.com注入了一个随请求变化的"Age"头。如果没有修改器,govcr默认的严格匹配器将无法匹配cassette上的track,并继续发送实时请求(并将其记录到cassette)。

安装

go get github.com/seborama/govcr/v17@latest

在代码中使用以下导入:

import "github.com/seborama/govcr/v17"

核心概念

govcr是Go http.Client的包装器。它可以将实时HTTP流量记录到文件(称为"cassettes"),并稍后从这些文件回放HTTP请求(“tracks”)而不是进行实时HTTP调用。

当使用govcr的http.Client时,请求会与cassette上的tracks匹配:

  • 如果cassette上存在匹配的track,则播放该track
  • 否则请求会执行到HTTP服务器的实时调用,然后记录到cassette供下次使用

完整示例

自定义HTTP客户端

// 完整示例请参考测试中的TestExample2
func TestExample2() {
    // 为应用创建自定义http.Transport
    tr := http.DefaultTransport.(*http.Transport)
    tr.TLSClientConfig = &tls.Config{
        InsecureSkipVerify: true, // 仅示例,不推荐
    }

    // 创建myApp实例
    app := &myApp{
        httpClient: &http.Client{
            Transport: tr,
            Timeout:   15 * time.Second,
        },
    }

    // 实例化VCR
    vcr := govcr.NewVCR(
        govcr.NewCassetteLoader(exampleCassetteName2),
        govcr.WithClient(app.httpClient),
    )

    // 注入VCR的http.Client包装器
    app.httpClient = vcr.HTTPClient()

    // 运行请求并显示统计信息
    app.Get("https://example.com/foo")
}

加密cassette

// 完整示例请参考测试中的TestExample4
vcr := govcr.NewVCR(
    govcr.NewCassetteLoader(exampleCassetteName4).
        WithCipher(
            encryption.NewChaCha20Poly1305WithRandomNonceGenerator,
            "test-fixtures/TestExample4.unsafe.key"),
)

自定义请求匹配器

vcr.SetRequestMatchers(
    govcr.DefaultMethodMatcher,
    govcr.DefaultURLMatcher,
    func(httpRequest, trackRequest *track.Request) bool {
        // 可以安全地修改输入:
        // 修改会影响其他RequestMatcher,但不会影响原始HTTP请求或cassette Tracks
        httpRequest.Header.Del("X-Custom-Timestamp")
        trackRequest.Header.Del("X-Custom-Timestamp")

        return govcr.DefaultHeaderMatcher(httpRequest, trackRequest)
    },
)

回放track修改器

// 完整示例请参考测试中的TestExample3
vcr := govcr.NewVCR(
    govcr.NewCassetteLoader(exampleCassetteName3),
    govcr.WithRequestMatchers(
        func(httpRequest, trackRequest *track.Request) bool {
            // 从比较中移除头部
            httpRequest.Header.Del("X-Transaction-Id")
            trackRequest.Header.Del("X-Transaction-Id")

            return govcr.DefaultHeaderMatcher(httpRequest, trackRequest)
        },
    ),
    govcr.WithTrackReplayingMutators(
        track.ResponseDeleteHeaderKeys("X-Transaction-Id"), // 不追加到现有值
        track.ResponseTransferHTTPHeaderKeys("X-Transaction-Id"),
    ),
)

运行模式

govcr支持多种操作模式:

  • 正常HTTP模式:从cassette回放如果有匹配的track,否则进行实时调用
  • 仅实时模式:从不从cassette回放
  • 离线模式:仅从cassette回放,如果没有匹配的track则返回传输错误
  • 只读模式:正常行为,但禁止录制到cassette

设置模式示例

// 正常模式(默认)
vcr := govcr.NewVCR(
    govcr.NewCassetteLoader(exampleCassetteName),
)
// 或
vcr.SetNormalMode()

// 仅实时模式
vcr := govcr.NewVCR(
    govcr.NewCassetteLoader(exampleCassetteName),
    govcr.WithLiveOnlyMode(),
)
// 或
vcr.SetLiveOnlyMode()

// 只读模式
vcr := govcr.NewVCR(
    govcr.NewCassetteLoader(exampleCassetteName),
    govcr.WithReadOnlyMode(),
)
// 或
vcr.SetReadOnlyMode(true) // `false`禁用选项

// 离线模式
vcr := govcr.NewVCR(
    govcr.NewCassetteLoader(exampleCassetteName),
    govcr.WithOfflineMode(),
)
// 或
vcr.SetOfflineMode()

统计信息

VCR提供一些统计信息。要访问统计信息,可以调用vcr.Stats(),其中vcr是从NewVCR(...)获得的ControlPanel实例。

运行测试

make test

govcr是一个功能强大的HTTP请求录制和回放库,可以大大简化测试过程,特别是在需要离线测试或模拟API响应时。通过灵活的配置选项,它可以适应各种测试场景。


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

1 回复

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


使用govcr实现HTTP请求录制与回放

govcr是一个Go语言库,用于记录和回放HTTP交互,非常适合离线测试场景。它允许你"录制"真实的HTTP请求和响应,然后在测试中"回放"这些交互,而不需要实际访问远程服务器。

安装govcr

go get github.com/seborama/govcr

基本用法

1. 录制HTTP交互

package main

import (
	"fmt"
	"net/http"

	"github.com/seborama/govcr"
)

func main() {
	// 创建一个新的VCR控制器
	vcr := govcr.NewVCR(
		"my_first_recording", // 录制文件名(不带扩展名)
		&govcr.VCRConfig{
			Client: &http.Client{}, // 使用标准http.Client
			RecordingMode: govcr.RecordingModeRecordOnly,
		},
	)

	// 使用VCR的HTTP客户端
	client := vcr.Client

	// 发出HTTP请求(会被录制)
	resp, err := client.Get("https://jsonplaceholder.typicode.com/posts/1")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	fmt.Println("Status:", resp.Status)
}

2. 回放录制的交互

package main

import (
	"fmt"
	"net/http"

	"github.com/seborama/govcr"
)

func main() {
	// 使用相同的录制文件名,但切换为回放模式
	vcr := govcr.NewVCR(
		"my_first_recording",
		&govcr.VCRConfig{
			Client:        &http.Client{},
			RecordingMode: govcr.RecordingModeReplayOnly,
		},
	)

	// 使用VCR的HTTP客户端
	client := vcr.Client

	// 发出HTTP请求(会从录制中回放)
	resp, err := client.Get("https://jsonplaceholder.typicode.com/posts/1")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	fmt.Println("Status:", resp.Status) // 会输出与录制时相同的响应
}

高级配置

自定义存储位置

vcr := govcr.NewVCR(
	"custom_location_recording",
	&govcr.VCRConfig{
		Client:        &http.Client{},
		RecordingMode: govcr.RecordingModeRecordOnly,
		CassettePath:  "./testdata/cassettes", // 自定义存储目录
	},
)

混合模式(录制新请求,回放已录制的)

vcr := govcr.NewVCR(
	"mixed_mode_recording",
	&govcr.VCRConfig{
		Client:        &http.Client{},
		RecordingMode: govcr.RecordingModeNewOnly, // 只录制新请求,回放已存在的
	},
)

请求匹配器

默认情况下,govcr会根据Method和URL匹配请求。你可以自定义匹配逻辑:

vcr := govcr.NewVCR(
	"custom_matcher",
	&govcr.VCRConfig{
		Client:        &http.Client{},
		RecordingMode: govcr.RecordingModeRecordOnly,
		RequestMatchers: govcr.RequestMatchers{
			// 自定义匹配函数
			func(httpRequest, trackRequest *govcr.Request) bool {
				// 在这里实现自定义匹配逻辑
				return httpRequest.Method == trackRequest.Method &&
					httpRequest.URL.String() == trackRequest.URL.String()
			},
		},
	},
)

实际测试示例

package main_test

import (
	"net/http"
	"testing"

	"github.com/seborama/govcr"
	"github.com/stretchr/testify/assert"
)

func TestAPI(t *testing.T) {
	vcr := govcr.NewVCR(
		"api_test",
		&govcr.VCRConfig{
			Client:        &http.Client{},
			RecordingMode: govcr.RecordingModeNewOnly,
		},
	)

	t.Run("get post", func(t *testing.T) {
		resp, err := vcr.Client.Get("https://jsonplaceholder.typicode.com/posts/1")
		assert.NoError(t, err)
		assert.Equal(t, http.StatusOK, resp.StatusCode)
		defer resp.Body.Close()
	})

	t.Run("create post", func(t *testing.T) {
		// 这里可以测试POST请求
	})
}

注意事项

  1. 敏感数据:录制的交互可能包含敏感信息(如API密钥),应考虑加密或手动清理。
  2. 过期数据:录制的响应可能过时,需要定期更新。
  3. 动态内容:对于包含时间戳或随机数的响应,可能需要自定义请求匹配器。
  4. 文件管理:录制文件会累积,应考虑在CI/CD流程中管理它们。

govcr是一个强大的工具,可以显著提高测试的可靠性和速度,特别是在依赖外部API的情况下。通过录制真实的HTTP交互,你可以创建确定性的测试,同时减少对外部服务的依赖。

回到顶部