跳到正文
cccskills
免费在 GitHub 公开

backend-testing

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/doughnut星标 50(GitHub 50 + cccskills 0)

实测评分 未实测

查看安装方法

包含的文件(1)

  • SKILL.md6.0 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Backend Testing Rules

Style ("small test" practice — stable boundary, data over mocks, focused assertions, concise makeMe): the unit-testing skill — follow that first.

Commands

Run backend verification from the repo root:

CURSOR_DEV=true nix develop -c pnpm backend:verify

When no database migration is involved, this is faster:

CURSOR_DEV=true nix develop -c pnpm backend:test_only

Always run all backend unit tests instead of a selected file or test case.

For dough-test-optimization, use backend:test_only as both the ordinary feedback measurement and profiling run. Per-test timings are the time attributes in backend/build/test-results/test/TEST-*.xml; keep any derived raw profile outside committed files. To count Spring context boots, temporarily add logging.level.org.springframework.test.context.cache=DEBUG to backend/src/test/resources/application.properties (a logback-test.xml logger is overridden by the test profile's logging.level.root=OFF); each rise in the logged missCount is one boot. Revert it afterwards.

Core Principles

Backend application of the "small test" style (unit-testing skill):

  1. Prefer controller (or other HTTP-stable-boundary) tests for behavior users see through HTTP. These tests often do not reference the internal class you edited; cover services/repos via realistic makeMe preconditions and the real DB.
  2. Test services and algorithms directly only when they are an independent, intentional domain-stable contract (pure logic or algorithms).
  3. Keep tests small and focused: one behavior per test and descriptive names that explain the behavior.

Controller-style example:

@Test
void shouldBeAbleToSaveNoteWhenValid() throws UnexpectedNoAccessRightException {
  Note note = makeMe.aNote().creatorAndOwner(userModel).please();
  final NoteRealm noteRealm = controller.show(note);
  assertThat(noteRealm.getId(), equalTo(note.getId()));
}

Prefer injecting the controller on ControllerTestBase (as above). Every Spring test of the test profile extends SpringTestBase (testability package), directly or through ControllerTestBase, so the suite shares one application context. Do not add @AutoConfigureMockMvc or extra @MockitoBean / @TestBean on a subclass unless that exact annotation mix already exists — each unique mix caches another ApplicationContext and Hikari pool; CI MySQL then fails with Too many connections while a local run still passes. To observe a package-private persistence table, query through EntityManager rather than opening a new MockMvc context.

Calling a controller method directly skips request binding. When a multipart or form DTO field name matters (for example a boolean the frontend sends by name), prove it with a request through an @Autowired MockMvc (multipart(...) with the real field name); SpringTestBase already configures MockMvc, so this adds no context.

Independent algorithm example:

@ParameterizedTest
@CsvSource({
  "moon,     partner of earth,          partner of earth",
  "Sedition, word sedition means this,  word [...] means this"
})
void clozeDescription(String title, String markdown, String expectedClozeDescription) {
  assertThat(
      new ClozedString(clozeReplacement, markdown).hide(new NoteTitle(title)).maskedContentAsMarkdown(),
      containsString(expectedClozeDescription));
}

Database Tests

  • Tests use actual database interactions inside the transaction that SpringTestBase rolls back after each test.
  • This gives confidence in database operations and repository behavior.
  • A @Formula field (for example Note.trashedInDatabase) is hydrated only when Hibernate loads the row from the database. An entity persisted or moved earlier in the same persistence context still carries the Java default, so a test that reads such a field through a loaded collection must makeMe.refresh(entity) first. Query-level predicates (Note.JPA_AVAILABLE) evaluate in SQL and need no refresh.
  • A test that signs in through the security filters creates a SPRING_SESSION row in Spring Session's own transaction, outside that rollback. Such a test class is non-transactional and deletes its session rows after each test (see DevelopmentAuthenticationConfigurationTest). Session cookie attributes apply only on the embedded server, so a test asserting them uses webEnvironment = RANDOM_PORT.

Example (TextContentValidatorTest): no restated Spring annotations; makeMe comes from the base.

class TextContentValidatorTest extends SpringTestBase {
  @Autowired Validator validator;

  @Test
  void defaultNoteIsValid() {
    assertThat(validator.validate(makeMe.aNote().inMemoryPlease()), is(empty()));
  }
}

MakeMe Builders

  • Use the central makeMe factory; chain methods; end with please() (or please(boolean) for persistence control).
  • Builders handle relationships and defaults — see unit-testing skill for when to extend them vs set fields in the test.
  • Ownership: prefer notebookOwnedBy(user) so aMemoryTrackerFor(note) inherits the owner.
Note note = makeMe.aNote()
                 .notebookOwnedBy(user)
                 .title("title")
                 .content("description")
                 .please();

Test Organization

  • Group related tests with @Nested.
  • Use @BeforeEach for common setup, keeping setup minimal and relevant to the group.
  • Mocking policy: unit-testing skill. Backend exception: external services only — mock OpenAIClient structured Responses output with OpenAiStructuredResponseMock in controller tests.

Assertions

  • Use assertThat with descriptive matchers; assertThrows for exceptions; @ParameterizedTest when inputs vary but the assertion focus stays the same.
  • Assertion scope and avoiding cross-test redundancy: unit-testing skill.

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。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日 更新

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日 更新

Database migration, Flyway, SQL migrations, schema changes, database versioning, migration files, squashing historical migrations. Use when adding or changing Flyway migrations or schema.

中文简介正在准备中。当前显示原文说明。

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

查看 nerds-odd-e 的全部技能

报告此技能的问题