Skip to content

sweetptios/swiftKentbeckTDD

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

119 Commits
 
 
 
 
 
 

Repository files navigation

Kent Beck 『테스트 주도 개발』 스터디 기록

실습 진행 방식

  • 개발 환경은 iOS/Swift 입니다.
  • 각 챕터별로 feature/chX 브랜치를 만들어 실습을 진행합니다.
    • 예: feature/ch3, feature/ch4, ...
  • 실습이 끝나면 main 브랜치에 머지하여 항상 최신 상태를 유지합니다.
  • 따라서 main 브랜치에는 모든 챕터의 누적된 결과물이 반영되어 있습니다.
  • 필요하다면 특정 챕터의 브랜치로 이동하여 해당 시점의 실습 코드를 확인할 수 있습니다.

배운 점

  • 테스트와 구현 단계를 더 작은 단위로 나눌 수 있음을 깨달았다.
  • 중복 제거를 목표로 코드를 지속적으로 개선했다.
  • p144까지 진행하면서 “어떻게 이런 구조가 만들어졌지?” 하는 신기함을 느꼈다.

8장: Dollar / Franc 중복 제거

  • 테스트가 하위 클래스에 의존하지 않고 상위 타입에 의존하도록 변경해도 동일하게 성공하도록 만들었다.
  • 이를 통해 어떤 모델 코드에도 영향을 주지 않고 상속 구조를 자유롭게 변경할 수 있게 되었다.

9장: 하위 클래스 제거 준비

  • 하위 클래스를 제거하기 위해 두 클래스의 currency 구현을 동일하게 리팩터링했다.
  • “불안하면 보폭을 좁히고, 답답하면 보폭을 넓혀라.” — TDD 과정 전반에서 지속적으로 적용해야 할 조율임을 배웠다.
  • 중복된 부분을 호출자(팩터리 메서드)로 옮겨 두 생성자를 일치시켰다.

10~11장: Money의 하위 클래스 제거

  • 하위 클래스에서 상위 클래스로 메서드를 올리기 전에, 먼저 모든 하위 클래스의 코드가 동일해지도록 리팩터링했다.
  • 구조가 바뀌면서 불필요해진 테스트는 리팩터링 과정에서 제거했다.

12장: 가짜 구현을 통한 탐색

  • 설계 방향이 명확하지 않을 때는 가짜 구현으로 시작하고, 이후 리팩터링하는 방식으로 접근했다.

13장: 서로 다른 화폐 간 합산 로직 시작

  • 큰 테스트를 작은 테스트로 나누어 진행했다.
    • 예: $5 + 10CHF$5 + $5
  • 모든 중복이 제거되기 전까지는 테스트를 완성된 것으로 보지 않았다.

14장: 라이브러리 연산 검증

  • 라이브러리 연산에 대한 가정을 테스트 코드로 작성해 직접 검증했다.

15장: $5 + 10CHF 구현

  • 테스트 코드의 반환 타입을 상위 타입으로 바꾸고, 발생하는 컴파일 에러를 해결하면서 해당 멤버를 상위 타입으로 옮기는 방식으로 리팩터링했다.

16장: Money를 Expression으로 일반화 🔥

  • TDD로 구현할 경우 테스트 코드의 줄 수와 모델 코드의 줄 수가 거의 비슷해진다.
  • TDD가 경제적이려면 매일 만들어내는 코드의 양이 두 배가 되거나, 동일한 기능을 절반의 코드로 구현해야 한다.
  • 또한 TDD와 기존 방식의 차이를 측정할 때는 디버깅, 통합, 설명에 걸리는 시간까지 포함해야 한다는 점을 깨달았다.

번역 이슈 (p147~148)

  • $5 + $5 연산에서 Money를 반환하는지 실험하기 위한 테스트 추가
public void testPlusSameCurrencyReturnsMoney() {
    Expression sum = Money.dollar(1).plus(Money.dollar(1));
    assertTrue(sum instanceof Money);  // Sum이 아닌 Money가 반환되길 기대
}
  • 책의 번역에서는 이 테스트를 통과시키기 위한 코드 예시가 모호했으나, 실제 의도는 아래와 같았다.
public Expression plus(Expression addend) {
    return new Sum(this, addend);
}
  • 하지만 인자가 Money일 경우, 그 통화가 동일한지 확인하는 분명하고도 깔끔한 방법은 제시되지 않았다.
  • 만약 설명대로 구현하면 다음과 같은 코드가 되지만, 이는 깔끔한 방법이라고 보기 어렵다.
public Expression plus(Expression addend) {
    if (addend instanceof Money && this.currency.equals(((Money)addend).currency)) {
        return new Money(this.amount + ((Money)addend).amount, currency);
    }
    return new Sum(this, addend);
}

17장: 테스트 커버리지와 품질

코드와 테스트의 함수 수와 줄 수가 비슷하다는 점을 확인했다.

회기성 복잡도 (Cyclomatic Complexity)

  • 프로그램의 제어 흐름에서 독립적인 경로의 수를 측정하는 지표.
  • if, switch, for, while, and, or 등이 많을수록 복잡도가 커진다.

문장 커버리지 (Statement Coverage)

  • 테스트 품질을 충분히 측정하기는 어렵지만 출발점이 될 수 있다.
  • TDD를 철저히 따르면 100% 문장 커버리지를 달성할 수 있어야 한다.
  • JProbe(www.sitraka.com/software/jprobe) 결과:
    • 단 하나의 메서드 Money.toString()만 커버되지 않았음.
    • 이는 실제 모델 코드가 아니라 디버깅을 돕기 위해 추가된 코드였다.

결함 삽입 (Defect Insertion)

  • 아이디어: 코드 한 줄의 의미를 바꾸면, 반드시 테스트가 실패해야 한다.
  • 수동으로 하거나 Jester 같은 도구를 사용할 수 있다.
  • Jester 결과:
    • Pair.hashCode()의 한 줄을 0으로 반환하도록 속여도 테스트가 실패하지 않음.
    • 하지만 0 대신 다른 상수를 반환하는 것은 프로그램 의미를 바꾸지 않는다는 점에서 실제 결함으로 보긴 어렵다.

추가 통찰

  • 테스트 커버리지를 높이는 또 다른 방법은 테스트 수를 늘리는 것이 아니라, 프로그램 로직을 단순화하는 것이다.

“… 입력의 모든 경우의 수를 따라가며 커버리지를 늘리기보다는,
코드를 단순화함으로써 동일한 테스트들이 더 많은 경우를 자연스럽게 커버하게 만든다.”


18장: Bootstrap

bootstrap
맨바닥에서부터 스스로 만들어 올리다.


19장: 메서드 수정 원칙

  • p172 — 한 번에 메서드 하나 이상 수정하지 않으면서 테스트를 통과시키는 방법을 찾도록 노력한다.

20장: 테스트 간 격리

  • 외부 자원을 setUp에서 할당했다면, 반드시 tearDown에서 반환해야 한다.
  • 호출된 메서드의 로그를 남기는 전략으로 테스트를 강화할 수 있다.
    • 항상 로그의 끝에 기록을 추가하면 메서드 호출 순서를 쉽게 알 수 있다.

21장: 다음 테스트 선택 기준

  • 다음에 구현할 테스트는
    1. 나에게 가르침을 줄 수 있는 것
    2. 내가 만들 수 있다는 확신이 드는 것
  • 새로운 테스트에서 문제가 생기면, 두 단계 뒤로 물러서서 더 단순한 테스트를 시도한다.

22장: 실패한 테스트 대응

  • 실패한 테스트를 발견하면, 더 세밀한 단위 테스트를 작성해 올바른 출력을 확인한다.

23장: 중복과 TestSuite

  • 중복은 언제나 나쁘다. (놓친 디자인 요소를 찾기 위해 일부러 만드는 경우 제외)
  • TestSuiteComposite Pattern으로 구현 → 테스트 하나와 집합을 동일하게 다룬다.

24장: 언어와 xUnit

  • 새로운 언어를 접하면 그 언어로 xUnit을 직접 만들어본다.
  • 보통 테스트 8~10개를 통과할 즈음이면 그 언어의 주요 기능을 대부분 경험하게 된다.

🔥 이해하기 어려웠던 문장 (p195, 원문)

“There is substantial duplication here, which we could eliminate
if we had a way of constructing a suite automatically given a test class.”

➡️ 번역:
“여기에는 상당한 중복이 있다.
만약 테스트 클래스를 주면 자동으로 수트를 구성할 수 있는 방법이 있다면, 그 중복을 없앨 수 있을 것이다.”

Section 3 - Patterns

보다 정확한 이해를 위해 원서로 학습하고 내용을 정리하고 있습니다.

25 테스트 주도 개발 패턴

26 빨간 막대 패턴

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors