tdd

star 0

Guide Test-Driven Development following Kent Beck's Red-Green-Refactor cycle and Tidy First principles. Use when developing features with tests, following Kotest BehaviorSpec with Korean Given-When-Then patterns. Covers Domain (pure logic), Application (UseCase with MockK), and Adapter (Controller/Repository) layer testing.

kjyy08 By kjyy08 schedule Updated 1/1/2026

name: tdd description: Guide Test-Driven Development following Kent Beck's Red-Green-Refactor cycle and Tidy First principles. Use when developing features with tests, following Kotest BehaviorSpec with Korean Given-When-Then patterns. Covers Domain (pure logic), Application (UseCase with MockK), and Adapter (Controller/Repository) layer testing.

TDD Workflow

Follow Kent Beck's TDD cycle with Tidy First principles for blog-server project.

Quick Start

1. Red → Write failing test 2. Green → Make it pass with minimal code 3. Refactor → Improve structure 4. Repeat

Always use Kotest BehaviorSpec with Korean Given-When-Then.

Critical Pattern: BehaviorSpec

class MemberTest : BehaviorSpec({
    Given("유효한 이메일과 사용자 이름이 주어졌을 때") {
        When("회원을 등록하면") {
            Then("회원 ID가 생성된다") {
                member.entityId shouldNotBe null
            }
        }
    }
})

Never use FunSpec or StringSpec - only BehaviorSpec with Korean text.

Workflow

1. Red: Write Failing Test

See tdd-cycle.md for details.

  • Write smallest test in Korean Given-When-Then
  • Run test: ./gradlew test --tests ClassName
  • Confirm it fails

2. Green: Make It Pass

  • Write minimal code
  • Run test: ./gradlew test --tests ClassName
  • Confirm it passes

3. Refactor: Improve

See tidy-first-principles.md for Structural vs Behavioral changes.

  • Remove duplication
  • Improve names
  • Run all tests: ./gradlew test
  • Confirm all pass

Test Patterns by Layer

See test-patterns.md for complete code examples.

Domain Layer

Pure domain logic, no Spring:

class EmailTest : BehaviorSpec({
    Given("빈 문자열이 주어졌을 때") {
        When("Email 객체를 생성하려고 하면") {
            val exception = shouldThrow<IllegalArgumentException> {
                Email("")
            }
            Then("예외가 발생한다") {
                exception.message shouldContain "Email cannot be blank"
            }
        }
    }
})

Value Object Checklist:

  • ✅ Valid value
  • ✅ Blank/empty validation
  • ✅ Boundary values
  • ✅ Format validation
  • ✅ Equality and hashCode

Aggregate Root Checklist:

  • ✅ Factory methods
  • ✅ Immutability
  • from() reconstruction
  • ✅ Method chaining

Application Layer

UseCase with MockK:

class RegisterMemberServiceTest : BehaviorSpec({
    Given("회원 등록 서비스가 주어졌을 때") {
        val memberRepository = mockk<MemberRepository>()
        val service = RegisterMemberService(memberRepository)

        When("회원을 등록하면") {
            every { memberRepository.save(any()) } returns savedMember

            val response = service.execute(command)

            Then("Repository의 save가 호출된다") {
                verify(exactly = 1) { memberRepository.save(any()) }
            }
        }
    }
})

Adapter Layer

Controller with Facade mock:

class MemberControllerTest : BehaviorSpec({
    Given("회원이 로그인한 상태에서") {
        val facade = mockk<MemberQueryFacade>()
        val controller = MemberController(facade, ...)

        When("회원 정보 조회를 요청하면") {
            every { facade.getCurrentMember().execute(any()) } returns response

            val result = controller.getCurrentMember(memberId)

            Then("성공 응답이 반환된다") {
                result.statusCode shouldBe HttpStatus.OK
            }
        }
    }
})

Tidy First: Separate Changes

Never mix Structural and Behavioral changes

See tidy-first-principles.md.

Structural: Rename, extract, move (no behavior change) Behavioral: New features, bug fixes (requires tests)

Rule: Structural first, then behavioral separately.

Commands

# Run all tests
./gradlew test

# Run specific test
./gradlew test --tests MemberTest

# Run with coverage
./gradlew test koverHtmlReport

# Verify 60% coverage
./gradlew koverVerify

References

Install via CLI
npx skills add https://github.com/kjyy08/luigi-log-server --skill tdd
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator