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

Api Test Case Laravel Package

lchrusciel/api-test-case

PHPUnit TestCase for Symfony API development. Extends WebTestCase with easy JSON/XML response matching (via php-matcher) and optional Alice/Doctrine fixtures loading. Supports a clear TDD workflow using expected response files and helpful diffs.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require --dev lchrusciel/api-test-case
    

    No additional configuration is required for basic usage.

  2. First Test Case: Create a test class extending JsonApiTestCase (for JSON APIs) or XmlApiTestCase (for XML APIs):

    namespace App\Tests\Controller;
    
    use ApiTestCase\JsonApiTestCase;
    
    class UserTest extends JsonApiTestCase
    {
        public function testGetUser()
        {
            $this->client->request('GET', '/api/users/1');
            $this->assertResponse($this->client->getResponse(), 'user_response');
        }
    }
    
  3. Expected Response File: Create a file at tests/Responses/Expected/user_response.json:

    {
        "id": "@integer@",
        "name": "@string@",
        "email": "user@example.com"
    }
    
  4. Run Tests:

    vendor/bin/phpunit
    

Key First Use Cases

  • TDD Workflow: Write tests first, then implement API endpoints.
  • Response Validation: Use assertResponse() to validate JSON/XML responses against expected files.
  • Dynamic Values: Use PHP-Matcher patterns (@string@, @integer@, etc.) for dynamic values like IDs or timestamps.

Implementation Patterns

Core Workflow

  1. Test-Driven API Development:

    • Write a test with assertResponse() pointing to a non-existent response file.
    • Implement the API endpoint to make the test pass.
    • Refactor as needed.
  2. Response Validation:

    // Basic assertion
    $this->assertResponse($response, 'file_name');
    
    // With custom HTTP status code
    $this->assertResponse($response, 'file_name', 201);
    
  3. Fixtures with Alice:

    • Define fixtures in tests/DataFixtures/ORM/books.yml:
      App\Entity\Book:
          book1:
              title: "Test Book"
              author: "Test Author"
      
    • Load fixtures in tests:
      public function testWithFixtures()
      {
          $this->loadFixturesFromFile('books.yml');
          $this->client->request('GET', '/api/books');
          $this->assertResponse($this->client->getResponse(), 'books_list');
      }
      
  4. Custom Assertions:

    • Use PHP-Matcher patterns in expected files:
      {
          "id": "@uuid@",
          "created_at": "@string@.isDateTime()"
      }
      
    • Validate nested structures:
      {
          "data": [
              {
                  "id": "@integer@",
                  "attributes": {
                      "name": "@string@"
                  }
              }
          ]
      }
      

Integration Tips

  • Symfony Kernel: Configure KERNEL_CLASS in phpunit.xml if using a custom kernel:

    <php>
        <server name="KERNEL_CLASS" value="App\Kernel" />
    </php>
    
  • Database Transactions: Enable Doctrine transactions in setUp() for isolated tests:

    protected function setUp(): void
    {
        parent::setUp();
        $this->enableDoctrineTransactions();
    }
    
  • Authentication: Use Symfony’s client->loginUser() or custom headers:

    $this->client->request('POST', '/api/login', [
        'json' => ['email' => 'test@example.com', 'password' => 'password']
    ]);
    
  • Environment-Specific Config: Override EXPECTED_RESPONSE_DIR or FIXTURES_DIR in phpunit.xml for different environments.


Gotchas and Tips

Common Pitfalls

  1. File Paths:

    • Ensure Expected response files are in the correct directory (default: ../Responses relative to the test class).
    • Fix: Use absolute paths in phpunit.xml or verify relative paths:
      <server name="EXPECTED_RESPONSE_DIR" value="%kernel.project_dir%/tests/Responses/Expected/" />
      
  2. Doctrine Fixtures:

    • Fixtures must be in tests/DataFixtures/ORM/ (default) or specify FIXTURES_DIR.
    • Fix: Add the bundle to config/bundles.php (Symfony 4+):
      Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['test' => true],
      Fidry\AliceDataFixtures\Bridge\Symfony\FidryAliceDataFixturesBundle::class => ['test' => true],
      
  3. PHP-Matcher Patterns:

    • Patterns like @string@ are case-sensitive and must match exactly.
    • Fix: Use specific patterns for complex validation:
      {
          "status": "@string@.equals('active')"
      }
      
  4. HTTP Status Codes:

    • assertResponse() defaults to 200. Omit the status code to use the default.
    • Fix: Explicitly pass the expected status:
      $this->assertResponse($response, 'file_name', 404);
      
  5. Doctrine Transactions:

    • Forgetting enableDoctrineTransactions() can lead to shared state between tests.
    • Fix: Add to setUp():
      $this->enableDoctrineTransactions();
      
  6. JSON Escaping:

    • ESCAPE_JSON is deprecated (default: false). Avoid relying on it for backward compatibility.

Debugging Tips

  • Detailed Errors: Use OPEN_ERROR_IN_BROWSER in phpunit.xml to open errors in a browser:

    <server name="OPEN_ERROR_IN_BROWSER" value="true" />
    <server name="OPEN_BROWSER_COMMAND" value="open %s" />
    
  • Response Dumping: Log raw responses for debugging:

    file_put_contents(
        sys_get_temp_dir() . '/debug_response.json',
        $this->client->getResponse()->getContent()
    );
    
  • Fixture Loading: Verify fixtures are loaded by checking the database or adding debug logs:

    $this->loadFixturesFromFile('books.yml');
    $this->assertDatabaseHas('book', ['title' => 'Test Book']);
    

Extension Points

  1. Custom Matchers: Extend PHP-Matcher by adding custom assertions to expected files:

    {
        "email": "@string@.matches('/^[^\s@]+@[^\s@]+\.[^\s@]+$/')"
    }
    
  2. Pre/Post-Test Hooks: Override setUp() or tearDown() for setup/teardown logic:

    protected function setUp(): void
    {
        parent::setUp();
        $this->client->request('POST', '/api/auth', ['json' => ['token' => 'test']]);
    }
    
  3. Custom Assertions: Create helper methods in your test class:

    protected function assertResponseContains($response, $key, $value)
    {
        $data = json_decode($response->getContent(), true);
        $this->assertArrayHasKey($key, $data);
        $this->assertEquals($value, $data[$key]);
    }
    
  4. Symfony Events: Dispatch events in tests to trigger custom logic:

    $this->client->getContainer()->get('event_dispatcher')->dispatch(
        new SomeEvent(),
        'some.event'
    );
    

Configuration Quirks

  • Temporary Directory: Set TMP_DIR in phpunit.xml to control log file storage:

    <server name="TMP_DIR" value="%kernel.project_dir%/var/log/tests/" />
    
  • Doctrine Support: Disable with IS_DOCTRINE_ORM_SUPPORTED=false if not using Doctrine:

    <server name="IS_DOCTRINE_ORM_SUPPORTED" value="false" />
    
  • PHPUnit 9+: Data providers may need adjustments due to BC breaks. Use dataProvider() with explicit types:

    public function testWithDataProvider()
    {
        $this->assertResponse($this->client->getResponse(), 'file_name');
    }
    
    public function dataProvider()
    {
        return [
            ['test1'],
            ['test2'],
        ];
    }
    
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.
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager