Skip to main content
Version: Next (unreleased)

Mock Provider

payment.MockProvider implements every gopay interface — the base Provider plus every optional capability — entirely in memory. Use it to test code that calls Client without hitting a real provider or needing API keys.

mock := payment.NewMockProvider()
client, _ := payment.NewClient(mock)

p, err := client.CreatePayment(ctx, payment.NewPaymentRequest(payment.USD(1000)).
WithPaymentMethod("pm_test"))

By default (WithAutoSucceed(true), WithAutoCapture(true)), a payment created with a PaymentMethodID succeeds immediately and, unless CaptureMethod is CaptureManual, is captured immediately too.

Simulating failures

Each operation has its own injectable error, checked before any other logic runs:

mock.WithCreateError(payment.ErrCardDeclined)
mock.WithCaptureError(payment.ErrProviderError)
mock.WithRefundError(payment.ErrRefundFailed)
mock.WithSetupError(payment.ErrSetupFailed)
mock.WithSubscriptionError(payment.ErrSubscriptionFailed)
mock.WithWebhookError(errors.New("bad signature"))
p, err := client.CreatePayment(ctx, req)
// err wraps payment.ErrCardDeclined

Clear an injected error the same way — call the With...Error method with nil.

Controlling success/capture behavior

mock.WithAutoSucceed(false) // payments stay PaymentStatusPending
mock.WithAutoCapture(false) // successful payments aren't auto-captured

Staging state directly

For tests that need a resource to already exist (e.g. testing GetPayment in isolation), set it directly instead of going through Create...:

mock.SetPayment(&payment.Payment{ID: "pi_test", Status: payment.PaymentStatusSucceeded})
mock.SetRefund(&payment.Refund{ID: "re_test", PaymentID: "pi_test"})
mock.SetCustomer(&payment.Customer{ID: "cus_test", Email: "jane@example.com"})
mock.SetSetupIntent(&payment.SetupIntent{ID: "seti_test"})
mock.SetPlan(&payment.Plan{ID: "plan_test"})
mock.SetSubscription(&payment.Subscription{ID: "sub_test"})
mock.AddInvoice(&payment.Invoice{ID: "inv_test"})

Inspecting and resetting state

payments := mock.Payments() // map[string]*Payment
refunds := mock.Refunds() // map[string]*Refund
customers := mock.Customers() // map[string]*Customer

mock.Reset() // clears all staged/created state and injected errors

MockProvider is safe for concurrent use, like every other provider.