Master backend architectures, REST API design, microservices, and server-side development across multiple languages. Use this as a central index to access specialized sub-skills.
中文简介正在准备中。当前显示原文说明。
Generates PHPUnit integration tests for PHP 8.5. Creates tests with real dependencies, database transactions, HTTP mocking. Supports repositories, API clients, message handlers.
中文简介正在准备中。当前显示原文说明。
查看安装方法安装前可以查看交给 AI 代理的指令内容。
Generates PHPUnit 11+ integration tests for PHP 8.5 infrastructure components.
<?php
declare(strict_types=1);
namespace Tests\Integration\{Namespace};
use {FullyQualifiedClassName};
use PHPUnit\Framework\Attributes\Group;
use Tests\IntegrationTestCase;
#[Group('integration')]
final class {ClassName}Test extends IntegrationTestCase
{
private {ClassName} $sut;
protected function setUp(): void
{
parent::setUp();
$this->sut = $this->getContainer()->get({ClassName}::class);
$this->beginTransaction();
}
protected function tearDown(): void
{
$this->rollbackTransaction();
parent::tearDown();
}
public function test_{operation}_{scenario}(): void
{
// Arrange
{arrange_code}
// Act
{act_code}
// Assert
{assert_code}
}
}
<?php
declare(strict_types=1);
namespace Tests;
use Doctrine\DBAL\Connection;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
abstract class IntegrationTestCase extends TestCase
{
private static ?ContainerInterface $container = null;
private ?Connection $connection = null;
protected function getContainer(): ContainerInterface
{
if (self::$container === null) {
self::$container = require __DIR__ . '/../config/container.php';
}
return self::$container;
}
protected function beginTransaction(): void
{
$this->connection = $this->getContainer()->get(Connection::class);
$this->connection->beginTransaction();
}
protected function rollbackTransaction(): void
{
$this->connection?->rollBack();
}
protected function getConnection(): Connection
{
return $this->connection ?? $this->getContainer()->get(Connection::class);
}
}
#[Group('integration')]
final class DoctrineOrderRepositoryTest extends IntegrationTestCase
{
private OrderRepositoryInterface $repository;
protected function setUp(): void
{
parent::setUp();
$this->repository = $this->getContainer()->get(OrderRepositoryInterface::class);
$this->beginTransaction();
}
protected function tearDown(): void
{
$this->rollbackTransaction();
parent::tearDown();
}
// Save and retrieve
public function test_saves_and_retrieves_order(): void
{
$order = OrderMother::pending();
$this->repository->save($order);
$found = $this->repository->findById($order->id());
self::assertNotNull($found);
self::assertTrue($order->id()->equals($found->id()));
}
// Update existing
public function test_updates_existing_order(): void
{
$order = OrderMother::pending();
$this->repository->save($order);
$order->addItem(ProductMother::book(), 1);
$order->confirm();
$this->repository->save($order);
$found = $this->repository->findById($order->id());
self::assertTrue($found->isConfirmed());
}
// Delete
public function test_deletes_order(): void
{
$order = OrderMother::pending();
$this->repository->save($order);
$this->repository->delete($order);
$found = $this->repository->findById($order->id());
self::assertNull($found);
}
// Not found
public function test_returns_null_for_nonexistent(): void
{
$result = $this->repository->findById(OrderId::generate());
self::assertNull($result);
}
// Query methods
public function test_finds_orders_by_customer(): void
{
$customerId = CustomerId::generate();
$order1 = OrderMother::forCustomer($customerId);
$order2 = OrderMother::forCustomer($customerId);
$order3 = OrderMother::forCustomer(CustomerId::generate());
$this->repository->save($order1);
$this->repository->save($order2);
$this->repository->save($order3);
$orders = $this->repository->findByCustomer($customerId);
self::assertCount(2, $orders);
}
// Pagination
public function test_paginates_results(): void
{
for ($i = 0; $i < 25; $i++) {
$this->repository->save(OrderMother::pending());
}
$page1 = $this->repository->findAll(limit: 10, offset: 0);
$page2 = $this->repository->findAll(limit: 10, offset: 10);
$page3 = $this->repository->findAll(limit: 10, offset: 20);
self::assertCount(10, $page1);
self::assertCount(10, $page2);
self::assertCount(5, $page3);
}
}
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
#[Group('integration')]
final class StripePaymentGatewayTest extends IntegrationTestCase
{
public function test_charges_card_successfully(): void
{
// Arrange
$mockResponse = new MockResponse(json_encode([
'id' => 'ch_123',
'status' => 'succeeded',
'amount' => 1000,
]), ['http_code' => 200]);
$httpClient = new MockHttpClient($mockResponse);
$gateway = new StripePaymentGateway($httpClient, 'sk_test_xxx');
// Act
$result = $gateway->charge(
Money::USD(1000),
new CardToken('tok_visa')
);
// Assert
self::assertTrue($result->isSuccessful());
self::assertSame('ch_123', $result->transactionId());
}
public function test_handles_declined_card(): void
{
// Arrange
$mockResponse = new MockResponse(json_encode([
'error' => [
'type' => 'card_error',
'code' => 'card_declined',
],
]), ['http_code' => 402]);
$httpClient = new MockHttpClient($mockResponse);
$gateway = new StripePaymentGateway($httpClient, 'sk_test_xxx');
// Act
$result = $gateway->charge(
Money::USD(1000),
new CardToken('tok_chargeDeclined')
);
// Assert
self::assertFalse($result->isSuccessful());
self::assertSame('card_declined', $result->errorCode());
}
public function test_handles_network_error(): void
{
// Arrange
$mockResponse = new MockResponse('', ['error' => 'Connection refused']);
$httpClient = new MockHttpClient($mockResponse);
$gateway = new StripePaymentGateway($httpClient, 'sk_test_xxx');
// Assert
$this->expectException(PaymentGatewayException::class);
// Act
$gateway->charge(Money::USD(1000), new CardToken('tok_visa'));
}
}
#[Group('integration')]
final class SendOrderConfirmationHandlerTest extends IntegrationTestCase
{
private SendOrderConfirmationHandler $handler;
private InMemoryMailer $mailer;
protected function setUp(): void
{
parent::setUp();
$this->mailer = new InMemoryMailer();
$this->handler = new SendOrderConfirmationHandler(
$this->getContainer()->get(OrderRepositoryInterface::class),
$this->mailer
);
$this->beginTransaction();
}
protected function tearDown(): void
{
$this->rollbackTransaction();
parent::tearDown();
}
public function test_sends_confirmation_email(): void
{
// Arrange
$order = OrderMother::confirmed();
$this->getRepository()->save($order);
$message = new SendOrderConfirmation($order->id()->toString());
// Act
$this->handler->__invoke($message);
// Assert
$sentEmails = $this->mailer->getSentEmails();
self::assertCount(1, $sentEmails);
self::assertSame($order->customerEmail()->value, $sentEmails[0]->to);
}
public function test_throws_for_nonexistent_order(): void
{
// Arrange
$message = new SendOrderConfirmation('nonexistent-id');
// Assert
$this->expectException(OrderNotFoundException::class);
// Act
$this->handler->__invoke($message);
}
}
#[Group('integration')]
final class RedisCacheAdapterTest extends IntegrationTestCase
{
private RedisCacheAdapter $cache;
protected function setUp(): void
{
parent::setUp();
$redis = $this->getContainer()->get(Redis::class);
$redis->flushDb();
$this->cache = new RedisCacheAdapter($redis);
}
public function test_stores_and_retrieves_value(): void
{
$this->cache->set('key', 'value', 60);
$result = $this->cache->get('key');
self::assertSame('value', $result);
}
public function test_returns_null_for_missing_key(): void
{
$result = $this->cache->get('nonexistent');
self::assertNull($result);
}
public function test_returns_default_for_missing_key(): void
{
$result = $this->cache->get('nonexistent', 'default');
self::assertSame('default', $result);
}
public function test_deletes_key(): void
{
$this->cache->set('key', 'value', 60);
$this->cache->delete('key');
self::assertNull($this->cache->get('key'));
}
public function test_expires_after_ttl(): void
{
$this->cache->set('key', 'value', 1);
sleep(2);
self::assertNull($this->cache->get('key'));
}
}
<!-- phpunit.xml -->
<php>
<env name="DATABASE_URL" value="sqlite:///:memory:"/>
</php>
use Testcontainers\Container\PostgreSqlContainer;
abstract class DatabaseTestCase extends TestCase
{
protected static ?PostgreSqlContainer $postgres = null;
public static function setUpBeforeClass(): void
{
self::$postgres = PostgreSqlContainer::make('15.0')
->withDatabase('test_db')
->start();
}
public static function tearDownAfterClass(): void
{
self::$postgres?->stop();
}
protected function getDsn(): string
{
return self::$postgres->getDsn();
}
}
Identify component type:
Determine test cases:
Generate base test case if needed:
Generate test class:
#[Group('integration')]Add test data helpers:
Provide:
The generator will:
还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
Master backend architectures, REST API design, microservices, and server-side development across multiple languages. Use this as a central index to access specialized sub-skills.
中文简介正在准备中。当前显示原文说明。
在每次回复中使用固定前缀并列出本次实际参考的指令/文件,便于校验是否遵循上下文与规则。
中文简介正在准备中。当前显示原文说明。
Automate 21risk tasks via Rube MCP (Composio). Always search tools first for current schemas.
中文简介正在准备中。当前显示原文说明。
Automate 2chat tasks via Rube MCP (Composio). Always search tools first for current schemas.
中文简介正在准备中。当前显示原文说明。
Arquitecto de Soluciones Principal y Consultor Tecnológico de Andru.ia. Diagnostica y traza la hoja de ruta óptima para proyectos de IA en español.
中文简介正在准备中。当前显示原文说明。
[00] META. Orchestrate skills into dynamic chains for complex tasks. Analyzes the task, discovers available skills, builds an optimal chain, explains why each skill is needed, and executes step-by-step with user confirmation. Use for any complex task requiring multiple thinking/research/analysis steps. Triggers on "plan this", "how to approach", "what's the strategy", "build a plan", or any multi-step problem requiring skill orchestration.
中文简介正在准备中。当前显示原文说明。