You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Stripe的PaymentIntent中Mock内部HTTP客户端?

解决Stripe paymentintent.New()单元测试Mock HTTP客户端的问题

直接使用paymentintent.New()顶层函数时,因为它内部会实例化默认的Stripe客户端,确实没法直接注入自定义的HTTP客户端做Mock。这里提供三种可行的解决方案:

方案1:重构代码,依赖注入paymentintent.Client(推荐)

Stripe Go SDK支持创建自定义的paymentintent.Client实例,它允许你传入自己配置的stripe.Client(包含自定义HTTP客户端)。通过依赖注入客户端实例,就能完全控制测试时的HTTP请求行为。

重构生产代码

把原来直接调用paymentintent.New()的逻辑,改为接收paymentintent.Client参数:

import (
    "github.com/stripe/stripe-go/v79"
    "github.com/stripe/stripe-go/v79/paymentintent"
)

// 重构后的函数,依赖注入客户端
func CreatePaymentIntent(client *paymentintent.Client, amount int64) (*stripe.PaymentIntent, error) {
    params := &stripe.PaymentIntentParams{
        Amount:   stripe.Int64(amount),
        Currency: stripe.String(string(stripe.CurrencyUSD)),
    }
    return client.New(params)
}

// 业务代码中使用默认客户端
func main() {
    stripe.Key = "your-stripe-secret-key"
    defaultPiClient := paymentintent.NewClient(stripe.DefaultClient)
    pi, err := CreatePaymentIntent(defaultPiClient, 1000)
    // 处理结果...
}

编写单元测试(用httptest模拟Stripe API)

用net/http/httptest搭建本地测试服务器,模拟Stripe的响应:

import (
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/stripe/stripe-go/v79"
    "github.com/stripe/stripe-go/v79/paymentintent"
    "github.com/stretchr/testify/assert"
)

func TestCreatePaymentIntent(t *testing.T) {
    // 启动测试服务器,模拟Stripe API响应
    testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 验证请求的合法性
        assert.Equal(t, http.MethodPost, r.Method)
        assert.Equal(t, "/v1/payment_intents", r.URL.Path)

        // 返回模拟的Payment Intent数据
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusOK)
        w.Write([]byte(`{
            "id": "pi_test_123",
            "amount": 1000,
            "currency": "usd",
            "status": "requires_payment_method"
        }`))
    }))
    defer testServer.Close()

    // 创建自定义Stripe客户端,指向测试服务器
    customStripeClient := &stripe.Client{
        Key:      "test-secret-key",
        BaseURL:  testServer.URL,
        HTTPClient: &http.Client{}, // 这里可以替换为mock的HTTP客户端
    }

    // 创建paymentintent客户端
    piClient := paymentintent.NewClient(customStripeClient)

    // 测试目标函数
    pi, err := CreatePaymentIntent(piClient, 1000)

    // 验证结果
    assert.NoError(t, err)
    assert.Equal(t, "pi_test_123", pi.ID)
    assert.Equal(t, int64(1000), pi.Amount)
}

方案2:临时替换全局默认客户端(无需大规模重构)

如果不想修改太多业务代码,可以临时替换stripe.DefaultClient,但要注意测试前后的清理,避免测试间的状态污染:

func TestCreatePaymentIntentWithDefaultClient(t *testing.T) {
    // 备份原始默认客户端
    originalDefaultClient := stripe.DefaultClient
    defer func() {
        // 测试结束后恢复原始客户端
        stripe.DefaultClient = originalDefaultClient
    }()

    // 启动测试服务器
    testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 返回模拟响应
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusOK)
        w.Write([]byte(`{"id": "pi_test_456", "amount": 2000, "currency": "usd"}`))
    }))
    defer testServer.Close()

    // 设置新的默认客户端
    stripe.DefaultClient = &stripe.Client{
        Key:      "test-key",
        BaseURL:  testServer.URL,
    }

    // 直接调用原来的CreatePaymentIntent函数(未重构版本)
    pi, err := CreatePaymentIntent(2000)

    assert.NoError(t, err)
    assert.Equal(t, "pi_test_456", pi.ID)
}

方案3:用Mock库直接Mock HTTP客户端

如果需要更细粒度的控制,可以用testify/mock这类库直接Mockhttp.Client的Do方法:

import (
    "io/ioutil"
    "net/http"
    "strings"
    "testing"

    "github.com/stripe/stripe-go/v79"
    "github.com/stripe/stripe-go/v79/paymentintent"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
)

// MockHTTPClient 实现http.Client的Do接口
type MockHTTPClient struct {
    mock.Mock
}

func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) {
    args := m.Called(req)
    return args.Get(0).(*http.Response), args.Error(1)
}

func TestCreatePaymentIntentWithMockClient(t *testing.T) {
    // 创建Mock HTTP客户端
    mockHTTPClient := new(MockHTTPClient)

    // 构造模拟响应
    mockResp := &http.Response{
        StatusCode: http.StatusOK,
        Header:     http.Header{"Content-Type": []string{"application/json"}},
        Body:       ioutil.NopCloser(strings.NewReader(`{"id": "pi_mock_789", "amount": 1500}`)),
    }

    // 预期Do方法被调用,返回模拟响应
    mockHTTPClient.On("Do", mock.Anything).Return(mockResp, nil)

    // 创建Stripe客户端,绑定Mock HTTP客户端
    stripeClient := &stripe.Client{
        Key:        "test-key",
        HTTPClient: mockHTTPClient,
    }

    piClient := paymentintent.NewClient(stripeClient)
    pi, err := CreatePaymentIntent(piClient, 1500)

    assert.NoError(t, err)
    assert.Equal(t, "pi_mock_789", pi.ID)
    // 验证Mock方法被调用
    mockHTTPClient.AssertExpectations(t)
}

内容的提问来源于stack exchange,提问作者Ritik Jain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 06:35:29