用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Dev-Toolbelt/dev-team-agents --skill test-pyramid命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | test-pyramid |
| description | Test pyramid — unit, integration, E2E patterns and pitfall guidance. |
tests/
unit/
domain/
OrderTest
PricingServiceTest
utils/
DateHelperTest
// Good unit test — isolated, no I/O, fast
function test_calculateDiscount_vipCustomer_gets15Percent() {
// Arrange
$pricing = new PricingService();
$customer = new Customer(tier: CustomerTier::VIP);
// Act
$discount = $pricing->calculateDiscount($customer, amount: 100.00);
// Assert
assert($discount === 15.00);
}
A unit test never touches a real database, external API, filesystem, message queue, cache server, or any other out-of-process dependency — not even a test/staging instance of one. If the code under test depends on one of these, inject the dependency and replace it with a mock/stub/fake in the test. A test that needs a running database or network call to pass is an integration test by definition, no matter which folder it lives in — move it to tests/integration/ (see below).
Mocks must model the real contract, not just return canned values: mirror the dependency's actual method signatures, error types, and edge-case responses (not-found, timeout, validation failure) — a mock that only ever returns the happy path hides bugs the real dependency would surface. Prefer typed fakes or in-memory implementations of a repository/client interface over ad-hoc stub objects when the interaction has more than one or two call sites.
tests/
integration/
api/
CreateOrderTest
GetUserProfileTest
repositories/
OrderRepositoryTest
services/
PaymentServiceTest
// Integration test — real DB, real HTTP
function test_createOrder_endpoint_persists_and_returns_201() {
// Arrange
$user = User::factory()->create();
$payload = ['items' => [['product_id' => 'uuid', 'qty' => 2]]];
// Act
$response = $this->actingAs($user)->postJson('/api/orders', $payload);
// Assert
$response->assertStatus(201);
$this->assertDatabaseHas('orders', ['user_id' => $user->id]);
}
tests/
e2e/
auth/
LoginFlowTest
checkout/
CompleteOrderTest
smoke/
HealthCheckTest
// E2E test — browser/HTTP client, full stack
test('user can complete checkout', async ({ page }) => {
// Arrange
await page.goto('/products');
// Act
await page.click('[data-testid="add-to-cart"]');
await page.click('[data-testid="checkout"]');
await page.fill('[name="card_number"]', '4242424242424242');
await page.click('[data-testid="confirm-order"]');
// Assert
await expect(page.locator('[data-testid="order-confirmation"]')).toBeVisible();
});
sleep(2)) — use waitFor / assertions instead| Pattern | When to use |
|---|---|
| Factories | Creating model instances with sensible defaults |
| Fixtures | Static, reusable data sets (e.g., seed a country list) |
| Builders | Complex object graphs with many relationships |
| Fakes | In-memory implementations of repositories/services |
Principle: create the minimum data needed for the test. Each test owns its data setup.
--exclude-group slow)