api-test Skill
Writes functional tests for API Platform endpoints using ApiTestCase to verify CRUD, validation, security, and multi-tenant isolation.
- GitHub Stars
- 29
- Dateien
- 1
- Letzter Commit
- 22. Okt. 2026
- Lizenz
- —
- Erlaubte Tools
- —
Was macht der api-test Skill?
api-test ist ein Agent Skill. Writes functional tests for API Platform endpoints using ApiTestCase to verify CRUD, validation, security, and multi-tenant isolation.
Zusammenfassung erzeugt aus der SKILL.md des Skills.
Über den api-test skill
Writing functional tests for API Platform endpoints is the primary task for developers using this skill. It automates the creation of test suites that verify CRUD operations, data validation, security protocols, and multi-tenant isolation. An agent should load this tool when a user needs to test a specific API resource, fix existing functional tests, or reproduce bugs found at an endpoint.
The skill utilizes ApiTestCase to generate PHP code for Symfony-based applications, handling complex requirements like setting up authentication headers or managing database fixtures. It also provides specialized support for Laravel environments by using ApiTestAssertionsTrait and RefreshDatabase. Whether working with Doctrine ORM or MongoDB, the tool produces structured test files in the appropriate directory to ensure resource integrity and proper schema management.
Was ein agent damit machen kann
- 1Verify CRUD operationsGenerate functional tests to ensure GET, POST, PATCH, and DELETE requests work correctly for a specific resource.
- 2Validate data constraintsCreate tests that check if the API returns a 422 status code when invalid data is submitted.
- 3Enforce multi-tenant securityDevelop tests to confirm that users cannot access or modify resources belonging to a different organization.
Geschrieben basierend auf dem SKILL.md des skills. Jeder use case wurde gegen ein zitat daraus geprüft.
So installierst du den api-test Skill
Jeder Befehl kopiert den Skill-Ordner in das Skills-Verzeichnis des Clients. Starte den Client neu oder beginne eine neue Session, um ihn zu laden.Den api-test Skill in Plugin installieren
/plugin marketplace add api-platform/skillset /plugin install api-platform@api-platform-skillset
Den api-test Skill in Claude Code installieren
~/.claude/skills/api-test/SKILL.md
$ npx degit api-platform/skillset/skills/api-test ~/.claude/skills/api-testDen api-test Skill in Claude Code (project) installieren
.claude/skills/api-test/SKILL.md
$ npx degit api-platform/skillset/skills/api-test .claude/skills/api-testDen api-test Skill in Codex installieren
~/.agents/skills/api-test/SKILL.md
$ npx degit api-platform/skillset/skills/api-test ~/.agents/skills/api-testDen api-test Skill in Gemini CLI installieren
~/.gemini/skills/api-test/SKILL.md
$ npx degit api-platform/skillset/skills/api-test ~/.gemini/skills/api-testDen api-test Skill in Claude.ai installieren
npx degit api-platform/skillset/skills/api-test api-test && zip -r api-test.zip api-test # claude.ai → Customize → Skills → + → Create skill → Upload a skill → api-test.zip
SKILL.md
Auf GitHub ansehenTesting API Platform Endpoints
Use ApiPlatform\Symfony\Bundle\Test\ApiTestCase for functional API tests.
Base Test Class
Create a base class that handles database setup and authentication:
<?php
namespace App\Tests;
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase as SymfonyApiTestCase;
use ApiPlatform\Symfony\Bundle\Test\Client;
class ApiTestCase extends SymfonyApiTestCase
{
protected function setUp(): void
{
parent::setUp();
// Reset database state for each test
$manager = static::getContainer()->get('doctrine')->getManager();
// For MongoDB: drop and recreate
// For ORM: use fixtures or transactions
}
/**
* Creates an authenticated client with test fixtures.
*/
public function createLoggedInClient(): Client
{
$manager = static::getContainer()->get('doctrine')->getManager();
// Create user, token, and required fixtures
$user = new User();
// ... set up user
$manager->persist($user);
$manager->flush();
// Return client with auth headers
return static::createClient([], [
'headers' => ['x-api-key' => 'test_token'],
]);
}
}
Basic CRUD Tests
class OrderTest extends ApiTestCase
{
public function testGetCollection(): void
{
$client = $this->createLoggedInClient();
$client->request('GET', '/orders');
$this->assertResponseIsSuccessful();
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
public function testCreate(): void
{
$client = $this->createLoggedInClient();
$client->request('POST', '/orders', [
'headers' => ['Content-Type' => 'application/ld+json'],
'json' => ['name' => 'Test Order', 'total' => 99.99],
]);
$this->assertResponseStatusCodeSame(201);
$data = $client->getResponse()->toArray();
$this->assertSame('Test Order', $data['name']);
}
public function testUpdate(): void
{
$client = $this->createLoggedInClient();
// Create then update
$client->request('POST', '/orders', [
'headers' => ['Content-Type' => 'application/ld+json'],
'json' => ['name' => 'Original'],
]);
$order = $client->getResponse()->toArray();
$client->request('PATCH', '/orders/' . $order['id'], [
'headers' => ['Content-Type' => 'application/merge-patch+json'],
'json' => ['name' => 'Updated'],
]);
$this->assertResponseIsSuccessful();
$this->assertSame('Updated', $client->getResponse()->toArray()['name']);
}
public function testDelete(): void
{
$client = $this->createLoggedInClient();
// ... create resource first
$client->request('DELETE', '/orders/' . $id);
$this->assertResponseStatusCodeSame(204);
}
}
Testing Validation
public function testCreateWithInvalidData(): void
{
$client = $this->createLoggedInClient();
$client->request('POST', '/orders', [
'json' => ['email' => 'not-valid'],
]);
$this->assertResponseStatusCodeSame(422);
$this->assertJsonContains([
'violations' => [
['propertyPath' => 'email', 'message' => 'This value is not a valid email address.'],
],
]);
}
Testing Authentication
public function testRequiresAuthentication(): void
{
// No auth headers — use raw createClient
$client = static::createClient();
$client->request('GET', '/orders');
$this->assertResponseStatusCodeSame(401);
}
Multi-Tenant Isolation Tests
Test that users can only access their own resources:
public function testIsolationBetweenUsers(): void
{
$client1 = $this->createLoggedInClient(); // User 1, Org 1
$client2 = $this->createSecondUserClient(); // User 2, Org 2
// User 1 creates a resource
$client1->request('POST', '/accounts', [
'headers' => ['Content-Type' => 'application/ld+json'],
'json' => ['address' => 'user1@example.com', 'password' => 'Pass123!'],
]);
$account = $client1->getResponse()->toArray();
// User 2 cannot read it
$client2->request('GET', '/accounts/' . $account['id']);
$this->assertResponseStatusCodeSame(404);
// User 2 cannot update it
$client2->request('PATCH', '/accounts/' . $account['id'], [
'headers' => ['Content-Type' => 'application/merge-patch+json'],
'json' => ['isActive' => false],
]);
$this->assertResponseStatusCodeSame(404);
// User 2 cannot delete it
$client2->request('DELETE', '/accounts/' . $account['id']);
$this->assertResponseStatusCodeSame(404);
// Collections are isolated
$client2->request('GET', '/accounts');
$collection = $client2->getResponse()->toArray();
$ids = array_column($collection['member'], 'id');
$this->assertNotContains($account['id'], $ids);
}
Testing Filters
public function testFilterByStatus(): void
{
$client = $this->createLoggedInClient();
// ... create test data with different statuses
$client->request('GET', '/orders?isActive=true');
$this->assertResponseIsSuccessful();
$data = $client->getResponse()->toArray();
foreach ($data['member'] as $order) {
$this->assertTrue($order['isActive']);
}
}
Common Assertions
$this->assertResponseIsSuccessful();
$this->assertResponseStatusCodeSame(201);
$this->assertJsonContains(['name' => 'Expected']);
$this->assertMatchesResourceItemJsonSchema(Order::class);
$this->assertMatchesResourceCollectionJsonSchema(Order::class);
Resetting the Schema Between Tests (ORM)
For a clean database per test, drop and recreate the schema in setUp(). API
Platform's own suite uses an internal ApiPlatform\Tests\RecreateSchemaTrait —
that namespace is not autoloaded in your app, so copy the mechanism rather than
importing it:
use Doctrine\ORM\Tools\SchemaTool;
protected function setUp(): void
{
parent::setUp();
$manager = static::getContainer()->get('doctrine')->getManager();
$metadata = $manager->getMetadataFactory()->getAllMetadata();
$schemaTool = new SchemaTool($manager);
$schemaTool->dropDatabase();
$schemaTool->createSchema($metadata);
}
For MongoDB ODM, drop the collections via
$manager->getSchemaManager()->dropDocumentCollection(...) instead.
Test File Location
Place tests in tests/Functional/ following the naming convention {ResourceName}Test.php.
Laravel
Laravel uses its own HTTP test client (PHPUnit Tests\TestCase or Pest), not
ApiTestCase. API Platform ships ApiPlatform\Laravel\Test\ApiTestAssertionsTrait
(adds assertJsonContains(), assertArraySubset(), getIriFromResource()). Use
RefreshDatabase for isolation and model factories for fixtures (not Doctrine
SchemaTool/fixtures).
<?php
namespace Tests\Feature;
use ApiPlatform\Laravel\Test\ApiTestAssertionsTrait;
use App\Models\Book;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class BooksTest extends TestCase
{
use RefreshDatabase, ApiTestAssertionsTrait;
public function testCreate(): void
{
$response = $this->postJson('/api/books', ['isbn' => '0099740915', 'title' => 'X']);
$response->assertStatus(201);
$this->assertJsonContains(['title' => 'X'], $response->json());
$book = Book::factory()->create();
$this->getJson($this->getIriFromResource($book))->assertStatus(200);
}
}
Key deltas: request helpers are getJson/postJson/patchJson/deleteJson;
assertions are $response->assertStatus(...), $response->assertHeader(...),
$this->assertDatabaseMissing(...). assertJsonContains() takes the decoded body
($response->json()). Isolation/validation(422)/auth tests use the same status-code
assertions; auth uses Sanctum/actingAs(), not custom headers. Pest is the default
and wraps the same trait via uses(RefreshDatabase::class, ApiTestAssertionsTrait::class).
Dateien in diesem Skill
1api-test Skill-Fragen
Wie installiere ich den api-test Skill in Claude Code?
Führe npx degit api-platform/skillset/skills/api-test ~/.claude/skills/api-test aus. Claude Code lädt Skills aus ~/.claude/skills (alle Projekte) oder .claude/skills (ein Projekt) und nutzt einen Skill, wenn seine Beschreibung zur Aufgabe passt.
Welche Clients können den api-test Skill nutzen?
Jeder Client, der das Agent Skills-Format liest: Claude Code, Codex, Gemini CLI und claude.ai (als ZIP hochladen). Skripte im Skill laufen nur dort, wo der Client Codeausführung erlaubt.
Does this skill support Laravel testing?
Yes, it provides guidance for Laravel using the ApiTestAssertionsTrait, RefreshDatabase, and model factories instead of ApiTestCase.