dist/cursor/magento2-commerce/skills/php-testing/SKILL.md
Write PHP tests with PHPUnit — unit tests, mocking, data providers, test doubles, assertions, and TDD practices. Use when writing tests for PHP code, whether in Magento or standalone PHP applications.
npx skillsauth add orcaqubits/agentic-commerce-claude-plugins php-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Fetch live docs: Web-search site:docs.phpunit.de phpunit 10 (or current version) for the latest PHPUnit documentation. Check https://phpunit.de/ for current version.
PHPUnit\Framework\TestCasetest or annotated #[Test]setUp() — runs before each testtearDown() — runs after each testsetUpBeforeClass() / tearDownAfterClass() — per-class lifecycleCommon assertions:
assertEquals($expected, $actual) — loose comparisonassertSame($expected, $actual) — strict comparison (type + value)assertTrue($value) / assertFalse($value)assertNull($value) / assertNotNull($value)assertInstanceOf($class, $object)assertCount($count, $array)assertArrayHasKey($key, $array)assertStringContainsString($needle, $haystack)expectException($class) — exception testingSupply multiple test cases to a single test method:
#[DataProvider('providerName')] attribute (PHPUnit 10+)Verify behavior — assert that methods were called with expected arguments:
$this->createMock(SomeClass::class)$mock->expects($this->once())->method('save')->with($entity)$mock->expects($this->never())->method('delete')Provide canned responses — no behavior verification:
$stub->method('getById')->willReturn($entity)$stub->method('getList')->willReturn($searchResults)willReturn($value) — always returns this valuewillReturnMap($map) — returns based on argument mappingwillReturnCallback($callable) — dynamic returnwillThrowException($exception) — throws on callwillReturnSelf() — returns the mock (for fluent APIs)willReturnOnConsecutiveCalls($val1, $val2, $val3) — different return per call.
Note:
willReturnOnConsecutiveCalls()is deprecated in PHPUnit 10.3+. UsewillReturn()with$this->onConsecutiveCalls()orwillReturnCallback()with a counter instead.
$this->expectException(NoSuchEntityException::class);
$this->expectExceptionMessage('Entity not found');
$repository->getById(999);
Don't test private methods directly — test through public methods. If a private method is complex enough to test independently, it should probably be extracted to its own class.
Create the class under test with mocked dependencies:
--coverage-html <dir> — generate HTML coverage report--coverage-text — terminal outputphpunit.xml or phpunit.xml.dist:
testGetByIdThrowsWhenNotFound()setUp() for common test setupFetch PHPUnit docs for exact assertion methods, mock API, and configuration options for your PHPUnit version before writing tests.
development
Build with Spree's headless Next.js storefront — the official `spree/storefront` repo (Next.js 16 App Router with Server Actions and Turbopack, React 19 Server Components, Tailwind CSS 4, TypeScript 5, `@spree/sdk`, Sentry), server-only auth (httpOnly JWT cookies + publishable key), MeiliSearch faceted catalog, one-page checkout with Apple/Google Pay/Klarna/Affirm/SEPA, multi-region market routing, GA4 + JSON-LD SEO, and Vercel/Docker deployment. Use when forking or customizing the storefront, or evaluating headless adoption.
tools
Build Spree extensions as Rails engines — gem scaffolding, `bin/rails g spree:extension`, mounting routes/migrations/assets, the modern `prepend` decorator pattern (`*_decorator.rb` with `self.prepended(base)`), generators (`spree:model_decorator`, `spree:controller_decorator`), the four customization surfaces in preference order (Events > Webhooks > Dependencies > Decorators), Spree::Dependencies for swapping service objects, gem release/versioning, and the deprecated Deface engine. Use when building a reusable Spree extension or adding non-trivial customization to an app.
development
Build with Spree's event bus and Webhooks 2.0 — `Spree::Events` publication, `Spree::Subscriber` DSL with `subscribes_to` and `on`, wildcard matching, lifecycle events (`{model}.created/.updated/.deleted` via `publishes_lifecycle_events`), the canonical event catalog (order.*, payment.*, shipment.*, product.*), Webhooks 2.0 endpoints, HMAC-SHA256 signing (`X-Spree-Webhook-Signature`), exponential-backoff retries, and Sidekiq job orchestration. Use when wiring event-driven business logic, building webhook consumers, or replacing ActiveSupport callback chains.
tools
Cross-cutting Spree development patterns — the customization preference hierarchy (Events > Webhooks > Dependencies > Decorators), `Spree::Dependencies` service-object swapping, the `_decorator.rb` + `prepend` + `self.prepended` idiom, idempotent subscribers and webhook receivers, multi-store scoping discipline, prefixed IDs, calculator polymorphism (shipping/promotion/tax share the base), service-object composition with `dry-monads` or simple results, why to avoid `class_eval` reopening and Deface, and Spree-on-Rails idioms (Hotwire/Turbo Stimulus, ActiveStorage, Action Cable, Sidekiq). Use when designing the architecture of a Spree extension or solving cross-cutting concerns.