本文へ移動
cccskills
無料GitHub で公開

php-testing

PHPUnit and Pest patterns for any PHP project: test structure, naming, data providers, test doubles (mocks/stubs/fakes), fixtures, and coverage targets. Stack-agnostic — referenced by every PHP plugin in the marketplace. Use this skill to: - Structure unit and integration tests with PHPUnit or Pest consistently. - Drive cases with data providers / datasets instead of copy-pasted test bodies. - Use test doubles with discipline — mock collaborators, not the system under test. - Set up and tear down fixtures cleanly and aim for a meaningful coverage target. Do NOT use this skill for: - PHP language idioms — see php-foundation:php-conventions. - Composer / autoloading — see php-foundation:composer-tooling. - Framework-specific test helpers (Laravel RefreshDatabase/actingAs, Symfony WebTestCase/KernelTestCase) — those are injected by the framework plugin's QA phase.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md5.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

PHP Testing Patterns (stack-agnostic)

Patterns for PHPUnit and Pest that apply to any PHP codebase. Detect which runner the project uses before writing tests: pestphp/pest in require-dev → Pest; otherwise PHPUnit. Both run on top of PHPUnit assertions.

Detection and running

grep -q pestphp/pest composer.json && echo pest || echo phpunit
vendor/bin/phpunit            # PHPUnit
vendor/bin/pest               # Pest
vendor/bin/phpunit --coverage-text   # coverage (needs Xdebug or PCOV)

Prefer a composer test script if one exists.

Test structure — Arrange / Act / Assert

PHPUnit (class-based):

<?php

declare(strict_types=1);

namespace App\Tests\Unit;

use App\Domain\Money;
use App\Domain\Currency;
use PHPUnit\Framework\TestCase;

final class MoneyTest extends TestCase
{
    public function test_it_adds_two_amounts_of_the_same_currency(): void
    {
        // Arrange
        $a = new Money(100, Currency::USD);
        $b = new Money(250, Currency::USD);

        // Act
        $sum = $a->add($b);

        // Assert
        self::assertSame(350, $sum->amount);
    }

    public function test_it_rejects_a_currency_mismatch(): void
    {
        $this->expectException(\InvalidArgumentException::class);

        (new Money(100, Currency::USD))->add(new Money(100, Currency::EUR));
    }
}

Pest (function-based, same engine):

<?php

declare(strict_types=1);

use App\Domain\Money;
use App\Domain\Currency;

it('adds two amounts of the same currency', function () {
    $sum = (new Money(100, Currency::USD))->add(new Money(250, Currency::USD));

    expect($sum->amount)->toBe(350);
});

it('rejects a currency mismatch', function () {
    expect(fn () => (new Money(100, Currency::USD))->add(new Money(100, Currency::EUR)))
        ->toThrow(InvalidArgumentException::class);
});

Naming and organisation

  • Tests live in tests/, namespace App\Tests\... (mapped via autoload-dev).
  • Mirror the source tree: src/Domain/Money.php → tests/Unit/Domain/MoneyTest.php.
  • Split tests/Unit (pure, no I/O) from tests/Integration / tests/Feature (DB, HTTP, filesystem).
  • PHPUnit method names: test_it_<behaviour>() or #[Test] attribute. Pest: it('<behaviour>'). Describe behaviour, not implementation.

Data providers / datasets

Drive many cases through one body instead of duplicating tests.

// PHPUnit
public static function discountCases(): array
{
    return [
        'no discount below 100' => [50, 0.0],
        '5% at 100'             => [100, 0.05],
        '15% at 1000'           => [1000, 0.15],
    ];
}

#[DataProvider('discountCases')]
public function test_discount_tiers(int $total, float $expected): void
{
    self::assertSame($expected, discountFor($total));
}
// Pest
it('applies discount tiers', function (int $total, float $expected) {
    expect(discountFor($total))->toBe($expected);
})->with([
    [50, 0.0],
    [100, 0.05],
    [1000, 0.15],
]);

Test doubles — mock collaborators, not the SUT

public function test_it_sends_a_receipt_after_charging(): void
{
    $gateway = $this->createMock(PaymentGateway::class);
    $gateway->expects(self::once())
        ->method('charge')
        ->with(self::equalTo(500))
        ->willReturn(new Receipt('rcpt_1'));

    $mailer = $this->createMock(Mailer::class);
    $mailer->expects(self::once())->method('send');

    $service = new CheckoutService($gateway, $mailer);
    $service->checkout($order);
}

Discipline:

  • Stub queries (return canned data); mock commands (assert they were called).
  • Mock the collaborators of the unit under test — never mock the class you are testing.
  • Don't over-specify: assert the interactions that matter, not every call.
  • Prefer real value objects and in-memory fakes over mocks for simple data.

Fixtures — setUp / tearDown

protected function setUp(): void
{
    parent::setUp();
    $this->repository = new InMemoryUserRepository();
}
  • Build fresh state per test; do not share mutable state across tests (order-dependence is a bug).
  • Use setUp() for common arrange steps; keep heavy fixtures out of unit tests.
  • For DB-backed tests, the framework plugin's QA phase supplies isolation (transactions/rollback) — apply that there.

Coverage target

  • Aim for ≥80% line coverage on changed code; 100% on domain/business logic.
  • Coverage is a floor, not a goal — a covered line is not necessarily an asserted behaviour.
  • Run vendor/bin/phpunit --coverage-text (requires PCOV or Xdebug). Report the number; do not chase the last few percent on glue code.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Angular 18-21 project structure, standalone components vs NgModule, control flow (@if/@for/@switch + *ngIf/*ngFor legacy), decorators, dependency injection (inject() function), lifecycle hooks, pipes, Angular Universal SSR pointer. Use this skill to: - Detect project style (standalone vs NgModule) and apply matching patterns. - Pick correct decorators and DI approach. - Use modern control flow (@if/@for/@switch) in Angular 17+ projects. - Apply `inject()` function over constructor injection where appropriate. - Wire bootstrap correctly (bootstrapApplication for standalone, AppModule for legacy). Do NOT use this skill for: - State management (see angular-state-and-rx). - Routing (see angular-routing). - Forms (see angular-forms). - Testing (see angular-testing).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

Angular forms: Reactive Forms (preferred — typed FormGroup/FormControl since Angular 14, FormBuilder, custom + async validators, FormArray, multi-step) and Template-driven (`[(ngModel)]` + FormsModule). Validation strategies, server error mapping, accessibility. Use this skill to: - Build Reactive Forms with typed FormGroup/FormControl. - Use FormBuilder для concise syntax. - Implement custom synchronous and async validators. - Wire FormArray for dynamic field lists. - Map server errors back to form fields. - Pick Reactive vs Template-driven (prefer Reactive). Do NOT use this skill for: - General conventions (see angular-conventions). - State management beyond forms (see angular-state-and-rx). - Routing (see angular-routing). - Testing forms (see angular-testing).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

Angular Router (built-in `@angular/router`) — route configuration for standalone and NgModule projects, functional guards (Angular 14.1+), lazy loading, route resolvers, typed params via signals/observables, programmatic navigation, route data and meta. Use this skill to: - Configure routes (standalone-style or NgModule-style). - Use functional guards (canActivate as function, preferred over class-based in 17+). - Lazy-load components or feature modules. - Implement auth guards via route meta + functional guards. - Read params/queries via `inject(ActivatedRoute)` + signals or RxJS. Do NOT use this skill for: - General conventions (see angular-conventions). - State management (see angular-state-and-rx). - Forms (see angular-forms). - Testing routes (see angular-testing).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

State management for Angular 18-21: signals (signal/computed/effect), services-as-state, NgRx Store + Effects + Selectors, NgRx Component Store, NgRx Signals (newer signal-based store). RxJS essentials — operators, async pipe, takeUntilDestroyed, signal/observable interop. Use this skill to: - Pick the right state tool (signals / services / NgRx variant / vue-query equivalent). - Use signals correctly (signal/computed/effect — when each). - Build a Pinia-style service-as-state singleton. - Set up NgRx Store + Effects + Selectors. - Use RxJS without leaking subscriptions (async pipe, takeUntilDestroyed, Subject patterns). - Bridge signals ↔ observables via toSignal / toObservable. Do NOT use this skill for: - General Angular conventions (see angular-conventions). - Routing state (see angular-routing). - Form state (see angular-forms). - Testing state (see angular-testing).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

Testing Angular 18-21: TestBed, component harnesses (@angular/cdk/testing), Karma+Jasmine (default historical) vs Jest (jest-preset-angular, modern), Angular Testing Library (RTL-style). HttpClient mocking via HttpTestingController. NgRx Effects testing. Cypress / Playwright e2e. Use this skill to: - Detect runner (Karma+Jasmine vs Jest) and configure correctly. - Write component tests with TestBed. - Use component harnesses for Material / custom UI components. - Mock HttpClient via provideHttpClientTesting + HttpTestingController. - Test signal-based inputs with componentRef.setInput(). - Test NgRx Effects with provideMockActions. Do NOT use this skill for: - General Angular conventions (see angular-conventions). - Routing patterns broadly (see angular-routing — covers testing routes briefly). - Form patterns broadly (see angular-forms).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

Shared conventions for every SDLC development-phase architect agent: hard rules, code quality bar, workflow steps (superpowers invocation, spec reading, codebase exploration, verification), and the report/compact-summary contract. Architects load this skill first, then apply their stack-specific instructions on top.

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

AratKruglik のスキルをすべて見る

このスキルの問題を報告する