책 소개
요약
더 좋은 코드를 작성하고 버그를 방지하고 싶은 소프트웨어 개발자를 위한 책이다. 테스트 용이성을 이해하고 이를 바탕으로 소프트웨어의 품질을 달성하는 방법을 다룬다. 또한 테스팅에 관한 다양한 기초사항과 기본 기법을 알려준다. 소프트웨어 작성 경험이 있다면 이 책의 내용을 실제 코드와 연관해 최대한 활용할 수 있을 것이다.
이 책에서 다루는 내용
■ 개발자 관점의 테스트 원칙 및 테스트 용어 이해
■ 잘 정립된 테스팅 기법과 모범 사례에 기반한 개발자 테스트
■ 테스트 용이성에 영향을 미치는 코드 구조의 인식
■ 단위 테스트에 대한 효과적인 명명법, 구성 및 실행 방법
■ 클래식 스타일 TDD와 목키스트(Mockist) 스타일 TDD의 필수 요소 이해
■ 테스트 더블을 모의 객체 프레임워크에 활용하는 방법과 활용하지 않는 방법
■ 계약에 따른 프로그래밍의 장점
■ 클래스, 컴포넌트, 계층 사이의 의존성 제어
■ 유사한 테스트가 많이 필요한 테스트 케이스, 시나리오 조합의 처리 기법
■ 제거할 수 없는 중복 코드의 관리 기법
■ 테스트 스위트의 능동적인 유지 관리 및 개선 방법
■ 통합, 시스템, 종단 수준의 고급 테스트 수행 방법
■ 조직적인 컨텍스트가 품질 보증에 미치는 영향
■ 애자일 팀에 적합한 균형 잡힌 효과적인 테스트 전략의 수립
이 책의 대상 독자
더 좋은 코드를 작성하고 버그 생성을 방지하고 싶은 개발자에게 적합한 책이다. 테스트 용이성을 인식하고 개발 스타일에 테스트 용이성을 적용해 소프트웨어의 품질을 달성하는 방법을 다룬다.
독자들은 아마도 더 나은 개발자가 되길 원하며 소프트웨어 테스팅을 알고 싶어하지만 시간도 없고 조직은 물론이고 동료의 지원도 받지 못하는 경우가 많다.
이 책은 초보자를 위한 책이 아니다. 다양한 기초사항과 기본적인 기법을 설명하지만 독자가 자신의 개발 환경과 빌드 시스템이 동작하는 방법을 알고 있고, 지속적인 통합과 정적 분석이나 코드 커버리지 도구와 같은 관련 도구에 익숙하다고 가정하고 설명한다. 이 책을 최대한 활용하려면 직업적인 소프트웨어 작성에 최소한 3년 이상 경험이 있어야 한다. 그래야 책의 내용이 익숙하다고 느낄 수 있고 이상적인 코드가 아닌 실제 코드를 샘플 코드에 연관시킬 수 있을 것이다.
많은 정보를 쉽게 이용할 수 있도록 돕는 것이 이 책의 목표이지만 지식을 통합하는 것은 독자의 몫이다.
이 책의 구성
1장, ‘개발자 테스팅’에서는 개발자와 관련된 다양한 테스팅 활동을 설명한다. 개발자들이 이러한 활동을 테스팅이라고 부르는지 여부와 상관없이 테스팅 활동은 개발자들이 자신의 프로그램이 동작하는지 여부를 검증하는 작업이다.
2장, ‘테스팅 목표, 스타일, 역할’에서는 테스팅에 대한 다양한 접근법을 설명하고 테스팅에 대한 비판과 지원의 차이점을 설명한다. 이 장의 후반부는 전통적 테스팅, 애자일 테스팅, 행위 주도 개발처럼 다양한 테스팅 버전을 설명하는 데 집중한다. 개발자 테스팅은 애자일 환경에서 널리 사용되는 지원 테스팅의 범주에 해당한다.
3장, ‘테스팅 용어’는 커다란 용어사전처럼 보일 수도 있다. 테스팅 커뮤니티에서 사용되는 용어와 테스팅 레벨 매트릭스, 테스트 타입, 애자일 테스트 사분면과 같은 공통적으로 사용되는 일부 모델을 설명한다. 모든 용어는 개발자 관점에서 설명되며 이들 중 일부 용어의 모호성과 다양한 해석은 해석이라기보다 인식이다.
4장, ‘개발자 관점의 테스트 용이성’에서는 개발자가 테스트 용이성(testability)에 왜 관심을 가져야 하는지를 다룬다. 테스트 가능한 소프트웨어와 이러한 소프트웨어에서 얻을 수 있는 혜택에 대한 내용이다. 테스트 용이성 품질 속성은 식별 가능성(observability), 조정 가능성(controllability), 미소성(smallness)으로 나눠 설명한다.
5장, ‘계약에 따른 프로그래밍’에서는 개발할 때 테스트의 작성 여부와 상관 없이 마음속 계약에 따른 프로그래밍(programming by contract)을 유지하는 경우의 장점을 설명한다. 이 기법은 호출하는 코드와 호출되는 코드 사이의 책임을 공식화한다. 이는 테스트 가능한 소프트웨어의 작성 관점에서도 중요하다. 5장에서는 모든 테스팅 프레임워크의 중심에 위치하는 어써션(assertions) 개념도 소개한다.
6장, ‘테스트 용이성의 드라이버’ 코드 내의 일부 구조는 테스트 용이성에 엄청난 영향을 미치기 때문에 이들을 인식 가능하게 만들고 명명하는 것이 중요하다. 6장에서는 직접 입•출력과 간접 입•출력, 상태, 시간적 커플링(Temporal coupling), 정의역 대 치역 비율(Domain-to-Range ratio)을 설명한다.
7장, ‘단위 테스팅’에서는 xUnit 기반 테스팅 프레임워크의 기본사항을 설명하면서 시작해 구조 테스트, 명명 테스트, 어써션의 적절한 사용, 제한 기반 어써션, 단위 테스팅 관련 다양한 기술과 같은 상위 주제로 확장한다.
8장, ‘명세 기반 테스트 기법’에서는 테스팅 도메인에서 일반적인 내용을 다룬다. 개발자 관점의 기본적인 테스팅 기법을 설명한다. 이 기법을 아는 것은 ‘내가 얼마나 많은 테스트를 작성해야 하는가?’와 같은 질문에 대답하는 데 필수다.
9장, ‘의존성’ 클래스, 컴포넌트, 계층이나 계층 사이의 의존성 모두 다양한 방법으로 테스트 용이성에 영향을 미친다. 9장에서는 의존성에 영향을 미치는 다양한 항목과 이들을 다루는 방법을 설명한다.
10장, ‘데이터 기반 테스트와 조합 테스트’에서는 겉보기에 많은 유사성을 가진 테스트들의 처리 방법이 필요한 경우를 설명한다. 10장에서는 이러한 문제를 해결하는 매개변수화 테스팅(parameterized tests) 관련 이론을 설명한다. 또한 테스트의 매개변수화를 더 깊이 있게 이야기하는 생성적 테스팅(Generative testing)도 설명한다. 마지막으로 테스터들이 테스트 케이스의 조합 확산(Combinatorial explosions)을 다루는 데 사용하는 기법들을 설명한다.
11장, ‘유사 단위 테스트’ 이 책은 실제로 이름에 의해 호출되는 단위 테스트처럼 최대한 빨리 단위 테스트 자격이 없는 일부 테스트를 찾아 수행하기 위해 단위 테스트의 정의에 의존한다. 차이점을 강조하고자 이 테스트들은 ‘빠른 중간 테스트(Fast medium tests)’라고 불린다. 일반적으로 이러한 테스트들은 서블릿 컨테이너, 메일 서버, 또는 인-메모리 데이터베이스와 같은 일부 유형의 경량 서버 설정에 포함된다.
12장, ‘테스트 더블’에서는 어떤 가상 객체 프레임워크도 사용하지 않고 전형적인 스텁, 가상 객체, 페이크, 더미와 같은 테스트 더블을 소개한다. 핵심은 다른 프레임워크를 배우지 않고도 테스트 더블을 아는 것이다. 12장에서는 상태 기반 테스팅과 상호작용 기반 테스팅의 차이점도 설명한다.
13장, ‘가상 객체 프레임워크’에서는 Moq, Mockito, 다양한 요구와 상황에서 테스트 더블 생성에 사용되는 Spock의 테스트 더블 기능(특히 스텁과 가상 객체)과 같은 실용적인 정보를 얻을 수 있다. 가상 객체 프레임워크의 사용과 관련 있는 약점과 안티 패턴도 포함한다.
14장, ‘테스트 주도 개발’에서는 긴 예제를 통해 고전적인 테스트 주도 개발을 소개한다. 예제는 테스트 (케이스) 작성 순서와 이들이 테스트를 통과하게 만드는 전략과 같은 TDD 기법의 다양한 세부사항을 설명하는 데 사용된다.
15장, ‘테스트 주도 개발 - 목키스트 스타일(Mockist Style)’ 테스트 주도 개발을 수행하는 방법은 여러 가지다. 15장에서는 대안적 방법을 설명한다. 이 방법은 테스트가 단일 클래스나 컴포넌트의 구현보다 시스템 설계가 더 중요한 경우에 적용 가능하다.
16장, ‘중복’에서는 코드의 중복이 테스트 용이성에 나쁜 이유를 설명한다. 하지만 때때로 중복은 독립성과 처리량을 달성하는 데 필요악이다. 2가지 주요 중복의 범주(기계적 중복과 지식의 중복)를 소개하고 자세히 설명한다.
17장, ‘테스트 코드로 작업하기’에서는 테스트 코드가 주석에 의존하기 전에 그리고 테스트를 삭제하기 전에 무엇을 해야 하는지 다룬다.
18장, ‘단위 테스트 그 이후’ 단위 테스트는 개발자 테스팅의 기초지만 퍼즐의 한 조각일 뿐이다. 오늘날의 소프트웨어 시스템은 복잡하고 때때로 다양한 수준의 추상화와 입자성 테스팅을 요구하는데, 여기서 통합 테스트, 시스템 테스트, 종단 간 테스트가 나타난다. 18장에서는 일련의 예제를 통해 이와 같은 테스트들을 소개하고 각 테스트의 특징을 설명한다.
19장, ‘테스트 아이디어와 휴리스틱’은 마지막 장으로 부록과의 경계에서 다양한 테스트 휴리스틱과 아이디어를 요약한다.
목차
목차
- 1장. 개발자 테스트
- 개발자 테스트
- 개발자 테스트 활동
- 개발자가 하지 말아야 하는 사항들
- 개발자 테스트의 정의
- 개발자 테스트와 개발 프로세스
- 1장 요약
- 2장. 테스팅의 목표, 스타일, 역할
- 테스팅과 검사
- 테스팅의 목적
- 테스팅 스타일
- 품질보증과 개발자 테스팅
- 2장 요약
- 3장. 테스팅 용어
- 에러, 결함, 실패
- 화이트박스 테스팅과 블랙박스 테스팅
- 테스트 분류
- 애자일 테스트 사분면
- 기타 테스팅 타입들
- 3장 요약
- 4장. 개발자 관점의 테스트 용이성
- 테스트 가능한 소프트웨어
- 테스트 용이성의 혜택
- 테스트 용이성의 정의
- 4장 요약
- 5장. 계약에 따른 프로그래밍
- 제약사항을 형식화하는 계약
- 계약에 따른 프로그래밍의 구현
- 계약 집행
- 5장 요약
- 6장. 테스트 용이성의 드라이버
- 직접 입•출력
- 간접 입•출력
- 상태
- 시간적 커플링
- 데이터 타입 및 테스트 용이성
- 정의역 대 치역 비율
- 6장 요약
- 7장. 단위 테스팅
- 왜 단위 테스트를 하는가?
- 단위 테스트란 무엇인가?
- 단위 테스팅 프레임워크의 수명 주기
- 네이밍 테스트
- 테스트 구성하기
- 어써션 메소드
- 예외 테스트
- 행위 주도 개발 스타일 프레임워크
- 7장 요약
- 8장. 명세 기반 테스트 기법
- 동등 분할
- 경계 값 분석
- 일부 데이터 타입에 대한 엣지 케이스와 실수
- 상태 전이 테스트
- 의사 결정 테이블
- 8장 요약
- 9장. 의존성
- 객체 사이의 관계
- 시스템 자원에 대한 의존성
- 계층 사이의 의존성
- 계층에 걸친 의존성
- 9장 요약
- 10장. 데이터 기반 테스팅과 조합 테스팅
- 매개변수화 테스트
- 이론
- 생성 테스팅
- 조합 테스트
- 10장 요약
- 11장. 유사 단위 테스트
- 예제들
- 효과
- 11장 요약
- 12장. 테스트 더블
- 스텁
- 페이크
- 모의 객체
- 스파이
- 더미
- 상태를 검증할 것인가? 행위를 검증할 것인가?
- 12장 요약
- 13장. 모의 객체 프레임워크
- 테스트 더블 구축하기
- 예측치 설정
- 상호작용 검증하기
- 오용, 남용, 기타 함정
- 13장 요약
- 14장. 테스트 주도 개발 – 고전적 스타일
- 간단한 검색 엔진 테스트
- 테스트 순서
- 레드 상태에서 그린 상태로 가는 전략들
- 도전사항
- 테스트 퍼스트 또는 테스트 라스트
- 14장 요약
- 15장. 테스트 주도 개발 – 모의 객체 활용자
- 다른 접근법
- 이중 루프 TDD
- 15장 요약
- 16장. 중복성
- 왜 중복이 나쁜가
- 중복의 활용
- 기계적 중복
- 지식 중복
- 16장 요약
- 17장. 테스트 코드로 작업하기
- 테스트에 주석 달기
- 테스트 삭제
- 17장 요약
- 18장. 단위 테스트 그 이후
- 단위 테스트가 아닌 테스트들
- 단위 테스트가 아닌 테스트들의 특성
- 요점사항과 사례
- 개발자 테스트 전략 결정
- 18장 요약
- 19장. 테스트에 대한 아이디어와 휴리스틱
- 고수준의 고려사항
- 저수준의 고려사항
- 19장 요약