옮긴이 머리말 xi
베타리더 후기 xii
추천사 xiv
시작하며 xvii
감사의 글 xix
이 책에 대하여 xxii
표지에 대하여 xxvi
CHAPTER 1 효율적이고 체계적인 소프트웨어 테스트 1
1.1 테스트를 하는 개발자와 하지 않는 개발자 2
1.2 개발자를 위한 효율적인 소프트웨어 테스트 14
__1.2.1 개발 과정에서의 효율적인 테스트 15
__1.2.2 반복 프로세스로서의 효율적 테스트 17
__1.2.3 개발에 먼저 집중하고 나서 테스트하기 17
__1.2.4 ‘제대로 된 설계’에 관한 미신 17
__1.2.5 테스트 비용 18
__1.2.6 효율적이면서 체계적이라는 것의 의미 18
__1.2.7 테스트 자동화의 역할 19
1.3 소프트웨어 테스트 원칙(테스트는 왜 이렇게 어려운가) 19
__1.3.1 완벽한 테스트는 불가능하다 20
__1.3.2 테스트를 그만둘 때를 파악하기 20
__1.3.3 가변성이 중요하다(살충제 역설) 20
__1.3.4 버그는 다른 곳에 비해 많이 발생하는 지점이 있다 21
__1.3.5 어떤 테스트를 하든지 결코 완벽하거나 충분하지 않다 21
__1.3.6 맥락이 핵심이다 22
__1.3.7 검증은 유효성 검사가 아니다 22
1.4 테스트 피라미드와 집중해야 할 부분 22
__1.4.1 단위 테스트 23
__1.4.2 통합 테스트 24
__1.4.3 시스템 테스트 26
__1.4.4 각 테스트 수준을 언제 사용해야 할까? 27
__1.4.5 단위 테스트를 선호하는 이유 28
__1.4.6 각 수준에서 무엇을 테스트해야 할까? 28
__1.4.7 테스트 피라미드에 동의하지 않는다면 30
__1.4.8 이 책에서 배우는 내용으로 버그를 모두 찾을 수 있을까? 32
1.5 연습문제 32
1.6 요약 35
CHAPTER 2 명세 기반 테스트 37
2.1 요구사항이 모든 걸 말한다 38
__2.1.1 1단계: 요구사항과 입출력에 대해 이해하기 41
__2.1.2 2단계: 여러 입력값에 대해 프로그램이 수행하는 바를 탐색하기 41
__2.1.3 3단계: 테스트 가능한 입출력과 구획을 탐색하기 43
__2.1.4 4단계: 경계 분석하기 46
__2.1.5 5단계: 테스트 케이스 고안하기 48
__2.1.6 6단계: 테스트 케이스 자동화하기 51
__2.1.7 7단계: 창의성과 경험을 발휘해서 테스트 스위트를 강화하기 53
2.2 간략히 살펴보는 명세 기반 테스트 55
2.3 명세 테스트로 버그 찾기 57
2.4 현업에서의 명세 테스트 67
__2.4.1 프로세스는 연속적이 아니라 반복적이어야 한다 67
__2.4.2 명세 테스트는 어느 정도로 수행해야 하는가? 67
__2.4.3 구획인가, 경계인가? 그것은 중요하지 않다! 68
__2.4.4 접점과 거점으로도 충분하지만 내점과 외점도 얼마든지 추가하자 68
__2.4.5 이해를 높이기 위해 입력을 변경해서 사용하자 68
__2.4.6 조합의 수가 폭발적으로 증가한다면 실용적이어야 한다 68
__2.4.7 무엇을 입력할지 모르겠다면 간단한 입력을 넣어보자 69
__2.4.8 관심 없는 입력에 대해 합리적인 값을 선택하자 69
__2.4.9 널과 예외 케이스는 의미가 있을 때만 사용하자 69
__2.4.10 테스트가 동일한 스켈레톤을 갖는 경우 매개변수화 테스트를 사용하자 70
__2.4.11 요구사항은 잘게 쪼갤 수 있다 70
__2.4.12 이것은 클래스와 상태에 어떻게 동작하는가? 70
__2.4.13 경험과 창의성의 역할 73
2.5 연습문제 73
2.6 요약 76
CHAPTER 3 구조적 테스트와 코드 커버리지 77
3.1 코드 커버리지, 올바른 방법 78
3.2 구조적 테스트 간략히 살펴보기 82
3.3 코드 커버리지 기준 83
__3.3.1 코드 줄 커버리지 83
__3.3.2 분기 커버리지 84
__3.3.3 조건 + 분기 커버리지 85
__3.3.4 경로 커버리지 86
3.4 복잡한 조건과 MC/DC 커버리지 기준 86
__3.4.1 추상적인 예제 86
__3.4.2 MC/DC를 달성하는 테스트 스위트 작성하기 87
3.5 반복문과 유사 구조 처리하기 90
3.6 기준 포함과 선택 91
3.7 명세 기반 테스트와 구조적 테스트: 실제 사례 92
3.8 경계 테스트와 구조적 테스트 98
3.9 구조적 테스트만 적용하는 것은 충분하지 않다 99
3.10 현업에서의 구조적 테스트 101
__3.10.1 왜 사람들은 코드 커버리지를 싫어할까? 101
__3.10.2 커버리지 100%가 의미하는 바는 무엇인가? 103
__3.10.3 어떤 커버리지 기준을 사용할 것인가 105
__3.10.4 표현식이 너무 복잡해서 단순화할 수 없다면 MC/DC를 고려하자 105
__3.10.5 그 외 커버리지 기준 107
__3.10.6 무엇을 수행하지 말아야 할까? 107
3.11 돌연변이 테스트 108
3.12 연습문제 111
3.13 요약 115
CHAPTER 4 계약 설계 117
4.1 사전 조건과 사후 조건 118
__4.1.1 단언 키워드 120
__4.1.2 강한 조건과 약한 조건 121
4.2 불변식 123
4.3 계약 변경과 리스코프 치환 법칙 127
__4.3.1 상속과 계약 129
4.4 계약에 의한 설계가 테스트와 어떤 관련이 있는가? 131
4.5 현업에서의 계약에 의한 설계 132
__4.5.1 강한 사전 조건 vs. 약한 사전 조건 132
__4.5.2 입력 유효성 검사인가, 계약인가? 아니면 둘 다인가? 133
__4.5.3 단언과 예외: 둘 중 하나를 사용해야 하는 경우 135
__4.5.4 예외 vs. 부드러운 반환값 136
__4.5.5 계약에 의한 설계를 사용하지 않는 경우 137
__4.5.6 사전 조건, 사후 조건, 불변식에 대해 테스트를 작성해야 할까? 137
__4.5.7 지원 도구 137
4.6 연습문제 138
4.7 요약 140
CHAPTER 5 속성 기반 테스트 141
5.1 예제 1: 합격 등급 프로그램 142
5.2 예제 2: unique 메서드 테스트 146
5.3 예제 3: indexOf 메서드 테스트 149
5.4 예제 4: Basket 클래스 테스트 157
5.5 예제 5: 복잡한 도메인 객체 생성 165
5.6 현업에서의 속성 기반 테스트 167
__5.6.1 예시 기반 테스트 vs. 속성 기반 테스트 167
__5.6.2 속성 기반 테스트의 일반적인 문제 168
__5.6.3 창의성이 핵심이다 169
5.7 연습문제 169
5.8 요약 170
CHAPTER 6 테스트 더블과 모의 객체 171
6.1 더미, 페이크, 스텁, 모의 객체, 스파이 174
__6.1.1 더미 객체 174
__6.1.2 페이크 객체 174
__6.1.3 스텁 174
__6.1.4 모의 객체 175
__6.1.5 스파이 175
6.2 모의 객체 프레임워크에 대한 소개 175
__6.2.1 의존성 스텁화 176
__6.2.2 모의 객체와 기댓값 182
__6.2.3 인수 포획 186
__6.2.4 예외 시뮬레이션 191
6.3 현업에서의 모의 객체 193
__6.3.1 모의 객체의 단점 193
__6.3.2 모의해야 하는 대상과 하지 말아야 하는 대상 195
__6.3.3 날짜 및 시간 래퍼 200
__6.3.4 소유하지 않은 것을 모의하기 203
__6.3.5 모의에 관한 외부 의견 205
6.4 연습문제 207
6.5 요약 208
CHAPTER 7 테스트 가능성을 위한 설계 211
7.1 도메인 코드에서 인프라 코드를 분리하기 212
7.2 의존성 주입과 제어 가능성 222
7.3 클래스 및 메서드를 관찰 가능하게 하기 225
__7.3.1 예제 1: 단언을 보조하는 메서드 도입하기 226
__7.3.2 예제 2: void 메서드의 행위를 관찰하기 227
7.4 의존성 전달 방법: 클래스 생성자와 메서드 매개변수 232
7.5 현업에서의 테스트 가능성 설계 235
__7.5.1 테스트 대상 클래스의 응집도 236
__7.5.2 테스트 대상 클래스의 결합 236
__7.5.3 복잡한 조건과 테스트 가능성 237
__7.5.4 private 메서드와 테스트 가능성 237
__7.5.5 정적 메서드, 싱글턴, 테스트 가능성 238
__7.5.6 육각형 아키텍처와 설계 기법으로서의 모의 객체 238
__7.5.7 테스트 가능성을 위한 설계에 대한 추가 자료 239
7.6 연습문제 239
7.7 요약 241
CHAPTER 8 테스트 주도 개발 243
8.1 첫 번째 TDD 세션 244
8.2 처음 맛본 TDD에 대한 고찰 254
8.3 현업에서의 TDD 255
__8.3.1 TDD인가, 아닌가? 255
__8.3.2 항상 TDD를 사용해야 할까? 256
__8.3.3 TDD는 모든 종류의 애플리케이션과 도메인에서 동작하는가 257
__8.3.4 TDD와 관련한 연구(학계에서 바라보는 TDD) 257
__8.3.5 다양한 TDD 학파 259
__8.3.6 TDD와 정식 테스트 260
8.4 연습문제 260
8.5 요약 262
CHAPTER 9 대규모 테스트 작성 263
9.1 대규모 테스트 사용 시기 264
__9.1.1 거대 구성요소에 대한 테스트 264
__9.1.2 코드 베이스 범위보다 큰 거대 구성요소 테스트 274
9.2 데이터베이스와 SQL 테스트 280
__9.2.1 SQL 쿼리에서 테스트해야 하는 것 281
__9.2.2 SQL 쿼리에 대한 자동 테스트 283
__9.2.3 SQL 테스트를 위한 인프라 설정 289
__9.2.4 모범 사례 292
9.3 시스템 테스트 293
__9.3.1 셀레늄 294
__9.3.2 페이지 객체 모델링 297
__9.3.3 패턴과 모범 사례 308
9.4 대규모 테스트에 대한 마지막 논의 312
__9.4.1 테스트를 어느 수준으로 해야 할까? 312
__9.4.2 비용/이득 분석을 수행하자 313
__9.4.3 수행은 되었지만 테스트되지 않은 메서드를 조심하자 314
__9.4.4 적합한 코드 인프라가 핵심이다 314
__9.4.5 DSL과 테스트를 작성하는 이해 관계자를 위한 도구 314
__9.4.6 다른 종류의 웹 시스템에 대한 테스트 314
9.5 연습문제 315
9.6 요약 316
CHAPTER 10 테스트 코드 품질 317
10.1 테스트 코드의 유지 보수성을 위한 원칙 318
__10.1.1 테스트는 빨라야 한다 318
__10.1.2 테스트는 응집력 있고 독립적이며 격리되어야 한다 318
__10.1.3 테스트는 존재 이유가 있어야 한다 319
__10.1.4 테스트는 반복 가능해야 하며 불안정하지 않아야 한다 319
__10.1.5 테스트의 단언문은 탄탄해야 한다 321
__10.1.6 테스트는 행위가 변경될 경우 깨져야 한다 321
__10.1.7 테스트는 단 하나의 명확한 이유로 실패해야 한다 322
__10.1.8 테스트는 작성하기 쉬워야 한다 322
__10.1.9 테스트는 읽기 쉬워야 한다 322
__10.1.10 테스트는 쉽게 수정하고 진화할 수 있어야 한다 327
10.2 테스트 냄새 328
__10.2.1 과다한 중복 328
__10.2.2 불명확한 단언문 329
__10.2.3 복잡하거나 외부에 있는 자원에 대한 잘못된 처리 330
__10.2.4 너무 범용적인 픽스처 331
__10.2.5 민감한 단언문 331
10.3 연습문제 335
10.4 요약 338
CHAPTER 11 마무리 339
11.1 비록 모델이 선형으로 보이더라도 반복이 핵심이다 339
11.2 버그 없는 소프트웨어 개발: 진실 혹은 거짓? 340
11.3 최종 사용자를 참여시키자 341
11.4 단위 테스트는 실제로 어렵다 341
11.5 모니터링에 투자하자 343
11.6 더 읽을거리 343
연습문제 정답 345
참고문헌 354
찾아보기 362