Навык api-test
Пишет функциональные тесты для эндпоинтов API Platform с использованием ApiTestCase для проверки CRUD, валидации, безопасности и изоляции в мультиарендных (multi-tenant) средах.
- Звёзды на GitHub
- 29
- Файлы
- 1
- Последний коммит
- 22 окт. 2026 г.
- Лицензия
- —
- Разрешённые инструменты
- —
Что делает навык api-test?
api-test — это Agent Skill. Пишет функциональные тесты для эндпоинтов API Platform с использованием ApiTestCase для проверки CRUD, валидации, безопасности и изоляции в мультиарендных (multi-tenant) средах.
Сводка сгенерирована из SKILL.md навыка.
О skill api-test
Основная задача разработчиков при использовании этого навыка — написание функциональных тестов для эндпоинтов API Platform. Он автоматизирует создание тестовых наборов для проверки CRUD-операций, валидации данных, протоколов безопасности и изоляции в мультиарендных средах. Агенту следует загружать этот инструмент, когда пользователю нужно протестировать конкретный API-ресурс, исправить существующие функциональные тесты или воспроизвести баги, обнаруженные на эндпоинте.
Навык использует ApiTestCase для генерации PHP-кода в приложениях на базе Symfony, обрабатывая такие сложные требования, как настройка заголовков аутентификации или управление фикстурами базы данных. Он также предоставляет специализированную поддержку для сред Laravel через ApiTestAssertionsTrait и RefreshDatabase. Независимо от использования Doctrine ORM или MongoDB, инструмент создает структурированные файлы тестов в соответствующих директориях для обеспечения целостности ресурсов и корректного управления схемой.
Что агент может делать с ним
- 1Проверка CRUD-операцийГенерация функциональных тестов для проверки корректности выполнения запросов GET, POST, PATCH и DELETE для конкретного ресурса.
- 2Валидация ограничений данныхСоздание тестов, проверяющих, возвращает ли API статус-код 422 при отправке некорректных данных.
- 3Обеспечение безопасности в мультиарендных средахРазработка тестов для подтверждения того, что пользователи не могут получать доступ к ресурсам или изменять их, если они принадлежат другой организации.
Написано на основе skill SKILL.md. Каждый сценарий использования проверен по цитате из него.
Как установить навык api-test
Каждая команда копирует папку навыка в каталог навыков клиента. Перезапустите клиент или начните новую сессию, чтобы загрузить его.Установка навыка api-test в Плагин
/plugin marketplace add api-platform/skillset /plugin install api-platform@api-platform-skillset
Установка навыка api-test в Claude Code
~/.claude/skills/api-test/SKILL.md
$ npx degit api-platform/skillset/skills/api-test ~/.claude/skills/api-testУстановка навыка api-test в Claude Code (project)
.claude/skills/api-test/SKILL.md
$ npx degit api-platform/skillset/skills/api-test .claude/skills/api-testУстановка навыка api-test в Codex
~/.agents/skills/api-test/SKILL.md
$ npx degit api-platform/skillset/skills/api-test ~/.agents/skills/api-testУстановка навыка api-test в Gemini CLI
~/.gemini/skills/api-test/SKILL.md
$ npx degit api-platform/skillset/skills/api-test ~/.gemini/skills/api-testУстановка навыка api-test в Claude.ai
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
Открыть на GitHubTesting 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).
Файлы в этом навыке
1Вопросы о навыке api-test
Как установить навык api-test в Claude Code?
Выполните npx degit api-platform/skillset/skills/api-test ~/.claude/skills/api-test. Claude Code загружает навыки из ~/.claude/skills (все проекты) или .claude/skills (один проект) и использует навык, когда его описание соответствует задаче.
Какие клиенты могут использовать навык api-test?
Любой клиент, который читает формат Agent Skills: Claude Code, Codex, Gemini CLI и claude.ai (загрузить как ZIP). Скрипты в навыке выполняются только там, где клиент разрешает выполнение кода.
Поддерживает ли этот навык тестирование в Laravel?
Да, он предоставляет рекомендации для Laravel с использованием ApiTestAssertionsTrait, RefreshDatabase и фабрик моделей вместо ApiTestCase.