6.9 KiB

Testing with Mollie API Client

Test Mode Configuration

Key Concepts

  • Test mode is automatically determined by API key prefix (test_ or live_)
  • Explicit testmode parameter available for OAuth scenarios
  • Configure at global client level or per individual request

Global Configuration

use Mollie\Api\MollieApiClient;

$mollie = new MollieApiClient();
$mollie->setApiKey("test_dHar4XY7LxsDOtmnkVtjNVWXLSlXsM");
$mollie->test(true); // Applies to all subsequent requests

Per-Request Configuration

// Payment request with test mode
$createPaymentRequest = new CreatePaymentRequest(/* ... */);
$mollie->send($createPaymentRequest->test(true));

// Endpoint collection example
$customer = $mollie->customers->get('cust_12345678', testmode: true);

API Mocking

Basic Usage

API responses can be simulated without network calls by using the MollieApiClient::fake() method. Each Request/Response pair passed to the fake method is consumed after a matching request.

Note

To keep pairs available for reuse after they've been matched, use the retainRequests parameter: MollieApiClient::fake([...], retainRequests: true)

use Mollie\Api\MollieApiClient;
use Mollie\Api\Fake\MockResponse;
use Mollie\Api\Http\Requests\GetPaymentRequest;

$client = MollieApiClient::fake([
    GetPaymentRequest::class => new MockResponse(
        body: [
            'resource' => 'payment',
            'id' => 'tr_xxxxxxxxxxxx',
            'mode' => 'test',
            'amount' => [
                'value' => '20.00',
                'currency' => 'EUR'
            ],
            'description' => 'Test',
            'status' => 'open',
            // ...
        ],
        status: 200
    )
]);

$payment = $client->send(new GetPaymentRequest('tr_xxxxxxxxxxxx'));

Sequence Mock Responses

To return different responses for the same request type, use SequenceMockResponse and pass MockResponse or Closure (which return MockResponse instances) in the order they should occur.

$client = MollieApiClient::fake([
    DynamicGetRequest::class => new SequenceMockResponse(
        MockResponse::ok(['first' => 'response']),
        MockResponse::ok(['second' => 'response']),
        function (PendingRequest $pendingRequest) {
            //...

            return MockResponse::ok(['third' => 'response']);
        }
    )
])

To verify that a request was sent, use `assertSent` or `assertSentCount`.

```php
$client->send(new GetPaymentRequest('tr_xxxxxxxxxxxx', embedRefunds: true));

$client->assertSent(GetPaymentRequest::class);
$client->assertSent(function (PendingRequest $pendingRequest, Response $response) {
    return $pendingRequest->query()->get('embed') === 'refunds';
});

$client->assertSentCount(1);

MockResponse Options

Configure responses using:

  • Arrays: Direct data structure
  • Strings: JSON payloads or predefined fixture names
  • Callables: Dynamic response generation or intercepting assertions
// Array response
MockResponse::created([
    'id' => 'tr_xxxxxxxxxxxx',
    'amount' => ['value' => '20.00', 'currency' => 'EUR']
]);

// Fixture response
MockResponse::created('payment');

// Dynamic response
MockResponse::created(function (PendingRequest $request) {
    return ['amount' => $request->hasParameter('amount') ? 10 : 20];
});

// Intercepting assertions
function (PendingRequest $request) use ($idempotencyKey) {
    $this->assertEquals($idempotencyKey, $request->headers()->get('Idempotency-Key'));

    return MockResponse::created('payment');
}

Working with Collections

Create paginated list responses:

use Mollie\Api\Resources\PaymentCollection;

$client = MollieApiClient::fake([
    GetPaginatedPaymentsRequest::class => MockResponse::list(PaymentCollection::class)
        ->add([
            'resource' => 'payment',
            'id' => 'tr_xxxxxxxxxxxx',
            'mode' => 'test',
            'amount' => [
                'value' => '20.00',
                'currency' => 'EUR'
            ],
            'description' => 'Test',
            'status' => 'open',
            // ...
        ])
        ->create()
]);

Handling Embedded Resources

Simulate HAL+JSON embedded resources using the _embedded property:

Key Concepts

  • Use MockResponse::resource() to start building a resource response
  • Chain embed() calls to add related collections
  • Maintain resource relationships with a fluent interface
use Mollie\Api\Resources\Payment;
use Mollie\Api\Resources\RefundCollection;
use Mollie\Api\Resources\ChargebackCollection;

$client = MollieApiClient::fake([
    GetPaymentRequest::class => MockResponse::resource(Payment::class)
        ->with([  // Main resource properties
            'resource' => 'payment',
            'id' => 'tr_xxxxxxxxxxxx',
            'amount' => [
                'value' => '20.00',
                'currency' => 'EUR'
            ]
        ])
        ->embed(RefundCollection::class)  // First embedded collection
            ->add([
                'resource' => 'refund',
                'id' => 're_12345',
                'amount' => [
                    'value' => '10.00',
                    'currency' => 'EUR'
                ]
            ])
        ->embed(ChargebackCollection::class)  // Second embedded collection
            ->add([
                'resource' => 'chargeback',
                'id' => 'chb_12345',
                'amount' => [
                    'value' => '20.00',
                    'currency' => 'EUR'
                ]
            ])
        ->create()
]);

// Resulting response will contain:
// - Payment details in main body
// - Refunds in _embedded.refunds
// - Chargebacks in _embedded.chargebacks

Error Response Mocking

Simulate API error responses using dedicated helper methods or the generic error builder:

Common Error Shortcuts

use Mollie\Api\Fake\MockResponse;

// 404 Not Found
$client = MollieApiClient::fake([
    GetPaymentRequest::class => MockResponse::notFound('No payment exists with token tr_xxxxxxxxxxx')
]);

// 422 Validation Error (with optional field reference)
$client = MollieApiClient::fake([
    CreatePaymentRequest::class => MockResponse::unprocessableEntity(
        detail: 'Amount must be at least €1.00',
        field: 'amount'
    )
]);

Generic Error Builder

// Custom status code example
$response = MockResponse::error(
    status: 403,
    title: 'Forbidden',
    detail: 'Insufficient permissions to access this resource'
);

// Special characters handling
$detail = 'Invalid parameter "recurringType" - did you mean "sequenceType"?';
$response = MockResponse::unprocessableEntity($detail, 'field');

Error Response Structure All errors follow Mollie's standardized format:

{
    "status": 404,
    "title": "Not Found",
    "detail": "No payment exists with token tr_xxxxxxxxxxx",
    "field": "amount"  // Only present for validation errors
}