Installation:
composer require bneumann/mock-api-bundle --dev
Register the bundle in config/bundles.php with ['test' => true].
Configure:
Create config/packages/test/bneumann_mock_api.yaml:
bneumann_mock_api:
mocks_path: "%kernel.project_dir%/tests/mocks"
Create a Mock File:
Define a YAML file (e.g., tests/mocks/stripe.yaml) with a mock response:
stripe_payment:
url: "https://api.stripe.com/v1/payments"
method: POST
response:
status: 200
body: '{"id": "mock_payment_id", "status": "succeeded"}'
First Use Case: In a test, use Symfony’s HTTP client as usual. The bundle will intercept requests matching the mock definition:
use Symfony\Contracts\HttpClient\HttpClientInterface;
public function testStripePayment(TestClient $client): void
{
$response = $client->request('POST', 'https://api.stripe.com/v1/payments', [
'body' => json_encode(['source' => 'tok_visa'])
]);
$this->assertEquals(200, $response->getStatusCode());
}
Mock Definition:
stripe.yaml, payment_gateway.yaml).stripe_payment_success:
url: "https://api.stripe.com/v1/charges"
method: POST
body: '{"amount": 1000, "currency": "usd"}'
response:
status: 200
body: '{"id": "ch_123"}'
stripe_payment_failure:
url: "https://api.stripe.com/v1/charges"
method: POST
body: '{"amount": 1000, "currency": "usd", "fail": true}'
response:
status: 402
body: '{"error": "Insufficient funds"}'
Test Integration:
TestClient or inject HttpClientInterface into test classes.
public function testPaymentGateway(TestClient $client): void
{
$response = $client->request('GET', 'https://api.example.com/balance');
$this->assertJson($response->getContent());
}
Dynamic Mocks:
// In a test setup method
$this->mockApi->addMock('custom_mock', [
'url' => 'https://api.example.com/webhooks',
'response' => ['status' => 200, 'body' => '{}']
]);
Environment-Specific Mocks:
mocks_path config to separate mocks by environment (e.g., tests/mocks/staging, tests/mocks/production).Mocking Authenticated Requests:
auth_required:
url: "https://api.example.com/secure"
method: GET
headers:
Authorization: "Bearer token123"
response:
status: 200
body: '{"data": "secret"}'
Reusable Mock Templates:
Mocking API Delays:
delay field to the mock response (if the bundle supports it; otherwise, use PHPUnit’s sleep() or a custom decorator).Integration with Factories:
user_profile:
url: "https://api.example.com/users/1"
response:
status: 200
body: |
{
"id": "{{ faker->numberBetween(1, 100) }}",
"name": "{{ faker->name }}"
}
Bundle Scope:
use statements with use function(Bneumann\MockApiBundle\Test\mockApi) or ensure it’s test-only.URL Matching:
# Hypothetical wildcard (not natively supported; may require customization)
stripe_webhook:
url: "https://api.stripe.com/v1/events/*"
method: POST
Request Body Matching:
created_at).YAML Syntax Errors:
Caching:
Header/Query Parameter Matching:
Unmatched Requests:
$this->mockApi->debug(); // Hypothetical method; check bundle docs
HttpClient with onError() to log unmatched requests:
$client->request('GET', 'https://api.example.com')->onError(function (ExceptionInterface $e) {
$this->fail("Unexpected API call: " . $e->getMessage());
});
Mock Overrides:
mocks_path is correct and accessible.url or response).Performance:
stripe.yaml, paypal.yaml) and load only what’s needed.Custom Matchers:
Matcher class or add a decorator.Dynamic Mocks via API:
$this->mockApi->addMock('dynamic_mock', [
'url' => 'https://api.example.com/dynamic',
'response' => ['status' => 200, 'body' => '{}']
]);
Response Templates:
user_list:
url: "https://api.example.com/users"
response:
status: 200
body: |
{{ users|json_encode }}
ResponseFactory to parse templates.Mock Priorities:
stripe_payment:
priority: high
url: "https://api.stripe.com/v1/payments"
Integration with Laravel:
MockApi::mock('stripe_payment
How can I help you explore Laravel packages today?