Testing X402 payment flows requires mocking blockchain interactions to avoid real transactions during development. This guide covers testing strategies for all OpenLibx402 packages.
# tests/test_payment_flow.pyimportpytestfromopenlibx402_core.testingimportMockSolanaPaymentProcessorfromopenlibx402_clientimportX402AutoClientfromsolders.keypairimportKeypair@pytest.fixturedefmock_processor():processor=MockSolanaPaymentProcessor()processor.balance=100.0# Set mock balancereturnprocessor@pytest.fixturedeftest_keypair():returnKeypair()@pytest.fixturedeftest_client(test_keypair,mock_processor):client=X402AutoClient(wallet_keypair=test_keypair)client.client.processor=mock_processorreturnclient@pytest.mark.asyncioasyncdeftest_auto_payment_flow(test_client,mock_processor):"""Test automatic payment handling"""response=awaittest_client.fetch("http://localhost:8402/premium-data")assertresponse.status_code==200assertlen(mock_processor.transactions)==1assertmock_processor.transactions[0].startswith("mock_tx_")@pytest.mark.asyncioasyncdeftest_insufficient_funds(test_client,mock_processor):"""Test insufficient funds error"""mock_processor.balance=0.01# Not enough for paymentwithpytest.raises(InsufficientFundsError)asexc_info:awaittest_client.fetch("http://localhost:8402/premium-data")assert"insufficient"instr(exc_info.value).lower()
// handler_test.gopackagemainimport("net/http""net/http/httptest""testing""github.com/stretchr/testify/assert")funcTestPremiumEndpoint(t*testing.T){handler:=setupHandler()t.Run("Returns 402 without payment",func(t*testing.T){req:=httptest.NewRequest("GET","/premium",nil)w:=httptest.NewRecorder()handler.ServeHTTP(w,req)assert.Equal(t,http.StatusPaymentRequired,w.Code)assert.Equal(t,"true",w.Header().Get("X-Payment-Required"))})t.Run("Returns 200 with payment",func(t*testing.T){req:=httptest.NewRequest("GET","/premium",nil)req.Header.Set("X-Payment-Authorization","transactionHash=mock_tx")w:=httptest.NewRecorder()handler.ServeHTTP(w,req)assert.Equal(t,http.StatusOK,w.Code)})}
# Good: Each test is independentdeftest_payment_success():processor=MockSolanaPaymentProcessor()# Test logicdeftest_payment_failure():processor=MockSolanaPaymentProcessor()# Test logic# Bad: Shared state between testsprocessor=MockSolanaPaymentProcessor()# Globaldeftest_payment_success():# Uses global processordeftest_payment_failure():# Uses same global processor
@pytest.mark.integrationasyncdeftest_full_payment_flow():"""Test complete flow from 402 to successful payment"""# 1. Start test serverserver=TestServer()server.start(port=8402)# 2. Create client with mock processorclient=X402AutoClient(keypair)client.client.processor=MockSolanaPaymentProcessor()# 3. Make requestresponse=awaitclient.fetch("http://localhost:8402/premium")# 4. Verifyassertresponse.status_code==200assert"data"inresponse.json()# 5. Cleanupserver.stop()