| sidebar_position | 6 |
|---|
The OpenApiValidation trait provides OpenAPI/Swagger validation functionality that can be used in any PHP class,
without requiring you to extend ApiTestCase.
PHP only allows single inheritance. If you have an existing test base class, you can't extend both:
// ❌ Can't do both!
class MyApiTest extends MyCompanyBaseTest // Your base class
class MyApiTest extends ApiTestCase // OpenAPI validation
// PHP doesn't support multiple inheritanceThe OpenApiValidation trait gives you all the OpenAPI validation functionality without inheritance constraints:
// ✅ Now you can have both!
class MyApiTest extends MyCompanyBaseTest
{
use OpenApiValidation;
// You now have access to all OpenAPI validation methods
}If you don't have a custom base class, just extend ApiTestCase:
<?php
use ByJG\ApiTools\ApiTestCase;
use ByJG\ApiTools\Base\Schema;
class MyApiTest extends ApiTestCase
{
public function setUp(): void
{
$schema = Schema::fromFile('/path/to/openapi.json');
$this->setSchema($schema);
}
public function testGetPet()
{
$request = new \ByJG\ApiTools\ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1');
$this->sendRequest($request);
}
}If you have a custom base class, use the trait:
<?php
use ByJG\ApiTools\OpenApiValidation;
use ByJG\ApiTools\Base\Schema;
use ByJG\ApiTools\ApiRequester;
class MyApiTest extends MyCompanyBaseTest // Your existing base class
{
use OpenApiValidation; // Add OpenAPI validation
public function setUp(): void
{
parent::setUp(); // Call parent setup if needed
$schema = Schema::fromFile('/path/to/openapi.json');
$this->setSchema($schema);
}
public function testGetPet()
{
$request = new ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1');
$this->sendRequest($request);
}
}You can combine multiple traits:
class MyApiTest extends TestCase
{
use OpenApiValidation; // OpenAPI validation
use DatabaseTransactions; // Laravel trait
use WithFaker; // Faker trait
public function testComplexScenario()
{
// Use database transactions
DB::beginTransaction();
// Use faker
$name = $this->faker->name;
// Use OpenAPI validation
$request = new ApiRequester();
$request
->withMethod('POST')
->withPath('/users')
->withRequestBody(['name' => $name])
->expectStatus(201);
$this->sendRequest($request);
DB::rollBack();
}
}// Your company's base test class
abstract class CompanyBaseTest extends TestCase
{
protected function authenticate(): string
{
// Company-specific authentication logic
return 'Bearer token123';
}
protected function getApiUrl(): string
{
return getenv('API_URL') ?: 'http://localhost:8080';
}
}
// Your API test using both
class UserApiTest extends CompanyBaseTest
{
use OpenApiValidation;
public function setUp(): void
{
parent::setUp();
$this->setSchema(Schema::fromFile(__DIR__ . '/openapi.json'));
}
public function testAuthenticatedRequest()
{
$request = new ApiRequester();
$request
->withMethod('GET')
->withPath('/user/profile')
->withRequestHeader([
'Authorization' => $this->authenticate() // Use parent method
])
->expectStatus(200);
$this->sendRequest($request);
}
}While the trait works best with PHPUnit (for convenience methods), you can use it with other frameworks:
// Pest PHP example
use ByJG\ApiTools\OpenApiValidation;
use ByJG\ApiTools\Base\Schema;
use ByJG\ApiTools\ApiRequester;
uses(OpenApiValidation::class);
beforeEach(function () {
$this->setSchema(Schema::fromFile('openapi.json'));
});
test('get pet endpoint', function () {
$request = new ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1');
$this->sendRequest($request);
});When you use the OpenApiValidation trait, you get these methods:
// Set the OpenAPI schema to validate against
$this->setSchema(Schema $schema): void
// Set a custom requester (optional)
$this->setRequester(AbstractRequester $requester): void
// Get the current requester instance
$this->getRequester(): AbstractRequester|null// Send and validate request (recommended)
$this->sendRequest(AbstractRequester $request): ResponseInterface
// Legacy method (deprecated, use sendRequest)
$this->assertRequest(AbstractRequester $request): ResponseInterface// Check that schema is configured (throws exception if not)
$this->checkSchema(): voidclass MultiApiTest extends TestCase
{
use OpenApiValidation;
public function testUserApi()
{
$this->setSchema(Schema::fromFile('user-api.json'));
$request = new ApiRequester();
$request->withMethod('GET')->withPath('/users');
$this->sendRequest($request);
}
public function testOrderApi()
{
$this->setSchema(Schema::fromFile('order-api.json'));
$request = new ApiRequester();
$request->withMethod('GET')->withPath('/orders');
$this->sendRequest($request);
}
}class FlexibleTest extends TestCase
{
use OpenApiValidation;
// No setUp method needed!
public function testWithInlineSchema()
{
$schema = Schema::fromFile('openapi.json');
$request = new ApiRequester();
$request
->withSchema($schema) // Schema on request
->withMethod('GET')
->withPath('/pet/1');
// No need to call setSchema() on test class
$this->sendRequest($request);
}
}If you're currently extending ApiTestCase and want to switch to the trait:
Before:
class MyTest extends ApiTestCase
{
// ...
}After:
class MyTest extends MyCustomBase // Or just TestCase
{
use OpenApiValidation;
// Everything else stays the same!
}That's it! All your existing tests will work without any other changes.
The trait automatically detects if it's being used in a PHPUnit TestCase and will execute PHPUnit assertions from convenience methods:
class MyTest extends TestCase // PHPUnit TestCase
{
use OpenApiValidation;
public function test()
{
$request = new ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1')
->expectStatus(200) // ✅ PHPUnit assertion will run
->expectJsonContains(['status' => 'available']); // ✅ Will run
$this->sendRequest($request);
}
}If you're not using PHPUnit, the convenience methods will still validate against the OpenAPI schema, but won't register PHPUnit assertions.
✅ Flexibility - Use with any base class
✅ Composition - Combine multiple traits
✅ Backward Compatible - ApiTestCase still works
✅ Clean Code - Separate concerns
✅ Testable - Easier to unit test
✅ Framework Agnostic - Works beyond PHPUnit
- Use
ApiTestCaseif you don't have a custom base class (simple) - Use
OpenApiValidationtrait if you have a custom base class (flexible) - Both provide the exact same functionality
- You can mix and match in the same project