본문으로 건너뛰기
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(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

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 / 1,000자

이 양식은 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의 스킬 모두 보기

이 스킬의 문제 신고