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

unit-testing

Small-test style for unit tests — stable boundary, data over mocks, focused assertions, concise makeMe (all packages). Use when writing or changing unit tests in any package.

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

nerds-odd-e/doughnutスター 50(GitHub 50 + cccskills 0)

実行スコア 未検証

インストール方法を見る

含まれるファイル(1)

  • SKILL.md7.6 KB

SKILL.md(原文)

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

"Small test" style

This repo’s automated tests are E2E or unit tests — nothing in between. Write unit tests in the "small test" style below.

A "small test" means: a fast, in-process unit test (JUnit, Vitest, Bach, …) that drives a stable boundary with crafted data/makeMe, exercises real lower-level production code, and mocks only external dependencies. Stack commands, entry points, and tooling stay in the package skills (frontend / frontend-testing, backend / backend-testing, cli, mcp-server).

Stable boundary

  • Drive the outermost (or domain-stable) interface. Prefer the public surface under test — e.g. a controller, mounted component, CLI run / runInteractive, MCP tool — or an interface that is itself a deliberate, domain-stable contract (pure algorithm, validation API). Do not add a test class per internal production class, and do not widen exports only so tests can reach helpers.
  • Cover lower layers with data, not with more test surfaces. Craft realistic, scenario-specific preconditions and fixtures so one boundary test exercises the real lower-level production routines. Prefer that over isolating each collaborator behind mocks or thin wrapper tests.
  • Build those fixtures with makeMe — keep construction concise (see below).
  • Do not mock unless external or exceptional. Mock only true external dependencies (third-party APIs, network services, and the like) or extremely rare special cases. Package rules name the allowed exceptions (OpenAIClient, frontend mockSdkService for the backend HTTP API, CLI spies on donut-api, etc.). Prefer the real database, real in-process collaborators, and real browser rendering inside the system under test.
  • Loud failures — Code that is allowed to fail loudly is not a unit-test subject for that failure. Policy: ADR 0006 Usage.

Focused assertions

  • One behavior per test. Assert only what this scenario uniquely establishes.
  • Canonical shape once. Shared post-conditions belong in one test. Sibling scenarios assert only their delta.
  • Different precondition ≠ re-assert unrelated post-condition. If outcome X is clearly independent of what changed in the setup, do not repeat X.
  • Prefer asserting the positive signal over “not the other message/alert” when the positive already distinguishes the case.
  • When a change removes something, the tests are those of the behavior that survives or replaces it. Write no test, assertion, fixture, or mock that observes the removed thing (not called, absent, ignored). Apply removal proof to each proof item. Rule: principle 7 in AGENTS.md / CLAUDE.md.
  • In loops (thresholds, retries, frame polls), assert the loop result, not the same intermediate outcome every iteration.
// ❌ every related case repeats the full payload
assertFalse(result.getAnswer().getCorrect());
assertThat(result.getAnswer().getOutcome(), is(ACCIDENTAL_MATCH));
assertThat(result.getMatchedNotes(), hasSize(1));

// ✅ canonical case asserts the shape; this case only the delta
assertThat(result.getAnswer().getOutcome(), is(ACCIDENTAL_MATCH));
// ❌ re-check section when the unique claim is “no link CTAs”
expect(wrapper.find('[data-testid="matched-notes-section"]').exists()).toBe(true)
expect(wrapper.findAll('[data-testid^="wiki-link-or-relationship-to-matched-note-"]')).toHaveLength(0)

// ✅
expect(wrapper.findAll('[data-testid^="wiki-link-or-relationship-to-matched-note-"]')).toHaveLength(0)

Removal proof

For a mixed change, inspect the individual assertions and observations in the proof table, slice Proof, and implementation brief. A scope statement about removal does not make a contradictory proof item acceptable.

  • Surviving or replacement behavior: retain the proof of button states, error feedback, and other promised outcomes, and carry it through all three handoff forms. A negative assertion can prove a surviving business outcome, such as silent completion; classify by what it establishes, not its syntax.
  • Actively enforced refusal: retain its rejection proof, including a read-only user's unavailable editing control. This establishes authorization behavior the product still promises.
  • Removed behavior or interface: delete its assertions and the fixtures, helpers, and mocks used only by them. Do not replace them with assertions that it is absent, not called, or ignored.
  • Sweep: record the one-time acceptance search and classified result as a reading in the plan, separately from surviving-behavior proof. Create no permanent absence test or checker.

The coordinator corrects inherited contradictions before delegation. An implementer or refactorer encountering one skips and reports that item while preserving valid proof; accepting a removal must not discard its surviving behavior's tests.

Destructive operations (hard deletes, delete migrations)

The concise-fixture guidance below is correct for behavior tests. For hard deletes and delete migrations, fixture completeness beats minimality — a bare target row with no children only proves row selection, not referential fan-out.

  • Hard-delete endpoints: build a row in every table that holds an FK into the deleted entity (directly or via CASCADE). Example: MemoryTrackerDeleteControllerTest uses makeMe.aConversation().forARecallPrompt(...) so deleting a tracker exercises the conversation → recall_prompt edge, not just the tracker row.
  • Delete migrations: same rule — seed every child table in the FK closure, not only rows the WHERE clause selects. While a gated migration is pending, pair it with a focused temporary test for the placeholder and row selection; remove that migration-only harness after confirmed production application.
  • Schema guard: DeletableEntityFkClosureTest catches restricting FKs without fixtures; it does not replace completeness tests for runtime delete paths.

Concise makeMe setup

  • Build fixtures with makeMe (donut-test-fixtures/makeMe on TS; backend MakeMe on Java). Rely on builder defaults when a value is unused in assertions and does not affect the logic under test. Exception: destructive operations above — do not minimize away FK children.
  • Do not create users, notebooks, or owners only to satisfy wiring if the builder already defaults them and the test never refers to them.
  • Prefer ownership helpers so dependents inherit the owner (e.g. backend notebookOwnedBy → tracker .by default).
  • Prefer builder APIs over post-construction mutation (e.g. .id(10), not note.id = 10).
  • Prefer domain-shaped helpers over field soup when the same shape repeats (e.g. .accidentalMatch(...), .overlap(...), .aliases(...)).
  • If a mandatory dependency or repeated fixture cannot be expressed concisely, extend the makeMe builder — do not leave verbose setup in every test.
// ❌
Notebook nb = makeMe.aNotebook().creatorAndOwner(currentUser.getUser()).please();
Note n = makeMe.aNote().notebook(nb).title("X").please();
makeMe.aMemoryTrackerFor(n).by(currentUser.getUser()).spelling().please();

// ✅
Note n = makeMe.aNote().notebookOwnedBy(currentUser.getUser()).title("X").please();
makeMe.aMemoryTrackerFor(n).spelling().please();
// ❌
const note = makeMe.aNote.please()
note.id = 10
note.noteTopology.id = 10

// ✅
const note = makeMe.aNote.id(10).please()

レビュー

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

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

backend

無料

Backend Java — Spring Boot controllers/services, JUnit controller tests, MakeMe. Read this first for any backend work. Use when working on the Java Spring backend.

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

nerds-odd-e/doughnut502026年10月26日 更新

Backend Java production code, Spring Boot controllers/services/repositories, controller return values, imports, schema ERD pointer. Use when editing backend production Java.

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

nerds-odd-e/doughnut502026年10月26日 更新

Backend Java tests, controller-level stable-boundary tests, JUnit, @Nested, MakeMe builders, @Transactional, parameterized tests. Use when writing or changing backend JUnit tests.

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

nerds-odd-e/doughnut502026年10月26日 更新

cli

無料

related to donut CLI. Use when working on donut-cli.

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

nerds-odd-e/doughnut502026年10月26日 更新

Set up and run the Donut dev environment on Cursor Cloud VM (no Nix). Use when working on Cloud VM, running tests on Cloud VM, or encountering command errors related to missing nix. Triggers on: cloud VM, cloud agent, no nix available, /workspace path.

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

nerds-odd-e/doughnut502026年10月26日 更新

Regenerate docs/database-erd.md from MySQL information_schema (Mermaid ERD: foreign keys and key columns). Use after Flyway schema changes, new migrations, or when the diagram is stale. Triggers on: database ERD, database-erd.md, export_database_erd, schema diagram, ER diagram after migration.

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

nerds-odd-e/doughnut502026年10月26日 更新

nerds-odd-e のスキルをすべて見る

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