grill-with-docs, improve-codebase-architecture, tdd, and triage kept non-spec markdown files at their skill root, in violation of skill-audit's file-structure.md rule (only SKILL.md/README.md belong at the root; everything else lives in scripts/, references/, assets/ or tests/). A root-level file is invisible to the ADR-0020 dangling-reference gate, which only resolves unqualified `references/...` pointers. - Moved and renamed to lowercase-kebab-case under references/: grill-with-docs (ADR-FORMAT.md, CONTEXT-FORMAT.md), improve-codebase-architecture (DEEPENING.md, INTERFACE-DESIGN.md, LANGUAGE.md), tdd (five files, casing was already fine), triage (AGENT-BRIEF.md, OUT-OF-SCOPE.md). - Updated every in-skill link to the new references/ paths, including link text that still showed the old uppercase filenames. - Fixed improve-codebase-architecture/SKILL.md's cross-skill citation of grill-with-docs's two files to the sanctioned possessive form with the references/ segment included. - Updated all four skills' README.md file tables to match. - Regenerated the flat content mirror via scripts/sync-plugin-content.sh --all. Fixes #122. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PDj6F7SPXzh3FtPN78dZ88
62 lines
1.6 KiB
Markdown
62 lines
1.6 KiB
Markdown
# Good and Bad Tests
|
|
|
|
## Good Tests
|
|
|
|
**Integration-style**: Test through real interfaces, not mocks of internal parts.
|
|
|
|
```typescript
|
|
// GOOD: Tests observable behavior
|
|
test("user can checkout with valid cart", async () => {
|
|
const cart = createCart();
|
|
cart.add(product);
|
|
const result = await checkout(cart, paymentMethod);
|
|
expect(result.status).toBe("confirmed");
|
|
});
|
|
```
|
|
|
|
Characteristics:
|
|
|
|
- Tests behavior users/callers care about
|
|
- Uses public API only
|
|
- Survives internal refactors
|
|
- Describes WHAT, not HOW
|
|
- One logical assertion per test
|
|
|
|
## Bad Tests
|
|
|
|
**Implementation-detail tests**: Coupled to internal structure.
|
|
|
|
```typescript
|
|
// BAD: Tests implementation details
|
|
test("checkout calls paymentService.process", async () => {
|
|
const mockPayment = jest.mock(paymentService);
|
|
await checkout(cart, payment);
|
|
expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
|
|
});
|
|
```
|
|
|
|
Red flags:
|
|
|
|
- Mocking internal collaborators
|
|
- Testing private methods
|
|
- Asserting on call counts/order
|
|
- Test breaks when refactoring without behavior change
|
|
- Test name describes HOW not WHAT
|
|
- Verifying through external means instead of interface
|
|
|
|
```typescript
|
|
// BAD: Bypasses interface to verify
|
|
test("createUser saves to database", async () => {
|
|
await createUser({ name: "Alice" });
|
|
const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
|
|
expect(row).toBeDefined();
|
|
});
|
|
|
|
// GOOD: Verifies through interface
|
|
test("createUser makes user retrievable", async () => {
|
|
const user = await createUser({ name: "Alice" });
|
|
const retrieved = await getUser(user.id);
|
|
expect(retrieved.name).toBe("Alice");
|
|
});
|
|
```
|