Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mock Api Bundle Laravel Package

bneumann/mock-api-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require bneumann/mock-api-bundle --dev
    

    Register the bundle in config/bundles.php with ['test' => true].

  2. Configure: Create config/packages/test/bneumann_mock_api.yaml:

    bneumann_mock_api:
        mocks_path: "%kernel.project_dir%/tests/mocks"
    
  3. 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"}'
    
  4. 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());
    }
    

Implementation Patterns

Core Workflows

  1. Mock Definition:

    • Use YAML files to define mocks for specific APIs (e.g., stripe.yaml, payment_gateway.yaml).
    • Structure mocks by URL, HTTP method, and request body (if needed).
    • Example for conditional mocking (e.g., success/failure scenarios):
      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"}'
      
  2. Test Integration:

    • Symfony HTTP Client: The bundle decorates the client in tests, so no additional setup is needed beyond requiring the package.
    • PHPUnit Tests: Use the 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());
      }
      
  3. Dynamic Mocks:

    • Override mocks per test by temporarily modifying the YAML files or using the bundle’s API (if exposed). For example:
      // In a test setup method
      $this->mockApi->addMock('custom_mock', [
          'url' => 'https://api.example.com/webhooks',
          'response' => ['status' => 200, 'body' => '{}']
      ]);
      
  4. Environment-Specific Mocks:

    • Use the mocks_path config to separate mocks by environment (e.g., tests/mocks/staging, tests/mocks/production).

Advanced Patterns

  1. Mocking Authenticated Requests:

    • Include headers or query parameters in the mock definition to match real-world requests:
      auth_required:
          url: "https://api.example.com/secure"
          method: GET
          headers:
              Authorization: "Bearer token123"
          response:
              status: 200
              body: '{"data": "secret"}'
      
  2. Reusable Mock Templates:

    • Store common mock structures (e.g., error responses, paginated data) in a base YAML file and extend them in test-specific files.
  3. Mocking API Delays:

    • Simulate latency by adding a delay field to the mock response (if the bundle supports it; otherwise, use PHPUnit’s sleep() or a custom decorator).
  4. Integration with Factories:

    • Combine with Laravel’s factories or Faker to generate dynamic mock responses:
      user_profile:
          url: "https://api.example.com/users/1"
          response:
              status: 200
              body: |
                  {
                      "id": "{{ faker->numberBetween(1, 100) }}",
                      "name": "{{ faker->name }}"
                  }
      

Gotchas and Tips

Pitfalls

  1. Bundle Scope:

    • The bundle only works in tests. Attempting to use it in production will fail silently or throw errors. Always prefix use statements with use function(Bneumann\MockApiBundle\Test\mockApi) or ensure it’s test-only.
  2. URL Matching:

    • URL matching is exact by default. Use regex or wildcards (if supported) for flexible matching:
      # Hypothetical wildcard (not natively supported; may require customization)
      stripe_webhook:
          url: "https://api.stripe.com/v1/events/*"
          method: POST
      
    • Tip: Use a tool like regex101.com to test URL patterns if extending functionality.
  3. Request Body Matching:

    • The bundle may not support partial body matching (e.g., ignoring timestamps). Ensure mocks match the exact request body sent in tests.
    • Workaround: Use a pre-test hook to normalize request bodies (e.g., remove dynamic fields like created_at).
  4. YAML Syntax Errors:

    • Invalid YAML in mock files will cause tests to fail silently or with cryptic errors. Validate files using a tool like yamllint.com.
  5. Caching:

    • Mock files are likely loaded once per test suite. Clear caches or restart the test process if changes to mocks aren’t reflected.
  6. Header/Query Parameter Matching:

    • If the bundle doesn’t support headers/query parameters in mock definitions, requests with these may not be matched. Tip: Extend the bundle or pre-process requests in tests.

Debugging

  1. Unmatched Requests:

    • If a request isn’t mocked, the bundle falls back to the real API. Add debug logs to verify mocks:
      $this->mockApi->debug(); // Hypothetical method; check bundle docs
      
    • Tip: Use Symfony’s 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());
      });
      
  2. Mock Overrides:

    • If mocks aren’t being applied, ensure:
      • The mocks_path is correct and accessible.
      • The YAML files are valid and loaded (check for typos in keys like url or response).
  3. Performance:

    • Large mock files or many mocks can slow down test suites. Tip: Split mocks into smaller files (e.g., stripe.yaml, paypal.yaml) and load only what’s needed.

Extension Points

  1. Custom Matchers:

    • Extend the bundle to support custom matchers (e.g., regex for URLs, partial body matching). Override the Matcher class or add a decorator.
  2. Dynamic Mocks via API:

    • If the bundle lacks runtime mock addition, create a service to dynamically inject mocks:
      $this->mockApi->addMock('dynamic_mock', [
          'url' => 'https://api.example.com/dynamic',
          'response' => ['status' => 200, 'body' => '{}']
      ]);
      
  3. Response Templates:

    • Add support for templating (e.g., Mustache or Twig) in mock responses to generate dynamic data:
      user_list:
          url: "https://api.example.com/users"
          response:
              status: 200
              body: |
                  {{ users|json_encode }}
      
    • Implementation: Extend the ResponseFactory to parse templates.
  4. Mock Priorities:

    • Allow mocks to override each other based on priority (e.g., test-specific mocks override global ones). Implement a priority field in YAML:
      stripe_payment:
          priority: high
          url: "https://api.stripe.com/v1/payments"
      
  5. Integration with Laravel:

    • If using Laravel, create a facade or helper to simplify mock usage:
      MockApi::mock('stripe_payment
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
babenkoivan/elastic-client
innmind/static-analysis
innmind/coding-standard
datacore/hub-sdk
alengo/sulu-http-cache-bundle
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
imbo/imbo-coding-standard
visualbuilder/filament-lottie
servicioslineaonce/starter-kit
atomcoder/laravel-reorderable
irajul/filament-shadcn-theme
agtp/agtp-php
agtp/mod-php
centraldesktop/protobuf-php