- 주문 목록에 음료 추가/ 삭제 기능
- 주문 목록 전체 지우기
- 주문 목록 총 금액 계산하기
- 주문 생성하기
- 작은 코드 단위를 독립적으로 검증하는 테스트
- 검증 속도가 빠르고, 안정적이다.
- 단위 테스트를 위한 테스트 프레임워크
- XUnit - kent Beck
Sunit(Smalltalk), Junit(Java), NUnit(.Net), PyUnit(Python) ...
- JUnit5의 assert 기능을 확장한 라이브러리
- 테스트 코드 작성을 원활하게 돕는 테스트 라이브러리
- 풍부한 API, 메서드 체이닝 지원
- 외부로 분리할수록 테스트 가능한 코드는 많아진다.
- 관측할 때마다 다른 값에 의존하는 코드 -> 현재 날짜/ 시간, 랜덤 값, 전역 변수/ 함수, 사용자 입력 등
- 외부 세계에 영향을 주는 코드 -> 표준 출력, 메시지 발송, 데이터베이스에 기록하기 등
- 같은 입력에 대해 항상 같은 출력을 반환하는 함수
- 외부 세상과 단절된 형태
- 테스트하기 쉬운 코드이다.
- 프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론
Red - Green - Refactor
- Red : 실패하는 테스트를 작성한다.
- Green : 테스트를 통과하는 최소한의 코드를 작성한다.
- Refactor : 테스트를 통과하는 코드를 리팩토링한다.
- 테스트 자체의 누락 가능성이 높다
- 특정 테스트 케이스만 검증할 가능성(해피 케이스)이 높다
- 잘못된 구현을 다소 늦게 발견할 가능성이 높다
- 복잡도가 낮은(유연하며 유지보수가 쉬운), 테스트 가능한 코드로 구현할 수 있게 한다.
- 쉽게 발견하기 어려운 엣지(Edge) 케이스를 놓치지 않게 해준다.
- 구현에 대한 빠른 피드백을 받을 수 있다.
- 과감한 리팩토링을 가능하게 한다.
- 테스트는 구현부 검증을 위한 보조 수단
- 테스트와 상호 작용하며 발전하는 구현부
클라이언트 관점에서의 피드백 을 주는 Test Driven
테스트는 문서 다.
- 프로덕션 기능을 설명하는 테스트 코드 문서
- 다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보완
- 어느 한 사람이 과거에 경험했던 고민의 결과물을 팀 차원으로 승격시켜서, 모두의 자산으로 공유할 수 있다.
- 명사의 나열보다는 문장 형태로 작성하는 것이 좋다.
A이면 B이다. A이면 B가 아니고 C다.
- 테스트 행위에 대한 결과까지 기술하는 것이 좋다.
- 도메인 용어를 사용하여 한층 추상화된 내용을 담는 것이 좋다.
메서드 자체의 관점보다 도메인 정책 관점으로
- 테스트의 현상을 중점으로 기술하지 말 것
성공한다, 실패한다와 같은 워딩은 피하는 것이 좋다.
- TDD에서 파생된 개발 방법
- 함수 단위의 테스트에 집중하기보다, 시나리오에 기반한 테스트케이스(TC) 자체에 집중하여 테스트한다.
- 개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 추상화 수준(레벨)을 권장
Given / When / Then
- Given : 시나리오 진행에 필요한 모든 준비 과정 (객체, 값, 상태 등)
- When : 시나리오를 진행하는 과정 (메서드 호출 등)
- Then : 시나리오 진행에 대한 결과 명시, 검증 (상태, 값 등) 어떤 환경에서(Given) 어떤 행동을 진행했을 때(When) 어떤 상태 변화가 일어난다.(Then)
- DisplayName에 명확하게 작성할 수 있다.
@DisplayName - 도메인 정책, 용어를 사용한 명확한 문장 Given / When / Then - 주어진 환경, 행동, 상태 변화 TDD vs. BDD Junit vs. Spock(Groovy) - BDD 기반이다.
- 여러 모듈이 협력하는 기능을 통합적으로 검증하는 테스트
- 일반적으로 작은 범위의 단위 테스트만으로는 기능 전체의 신뢰성을 보장할 수 없다.
- 풍부한 단위 테스트 & 큰 기능 단위를 검증하는 통합 테스트
- 객체 지향 패러다임과 관계형 DB 패러다임의 불일치를 해결하기 위한 기술
- 이전에는 개발자가 객체의 데이터를 한땀한땀 매핑하여 DB 저장 및 조회(CRUD) 작업을 수행했다.
- ORM을 사용함으로써 개발자는 단순 작업을 줄이고, 비즈니스 로직에 집중할 수 있다.
- Java 진영의 ORM 기술 표준
- 인터페이스이고, 여러 구현체가 있지만 보통 Hibernate를 많이 사용한다.
- 반복적인 CRUD SQL을 생성 및 실행해주고, 여러 부가 기능들을 제공한다.
- 편리하지만 쿼리를 직접 작성하지 않기 때문에, 어떤식으로 쿼리가 만들어지고 실행되는지 명확하게 이해하고 있어야 한다.
- Spring 진영에서는 JPA를 한번 더 추상화한 Spring Data JPA 제공
- QueryDSL과 조합하여 많이 사용한다.(타입체크, 동적쿼리)
- @Entity, @Id, @Column
- @ManyToOne, @OneToMany, @OneToOne, @ManyToMany(일대다 - 다대일 관계로 풀어서 사용하는 것이 좋다.)
- Data Access의 역할
- 비즈니스 가공 로직이 포함되어서는 안된다. Data에 대한 CRUD에만 집중한 레이어
- 비즈니스 로직을 구현하는 역할
- Persistence Layer와의 상호작용(Data를 읽고 쓰는 행위)을 통해 비즈니스 로직을 전개시킨다.
- 트랜잭션을 보장해야 한다.
- Dummy : 아무 것도 하지 않는 깡통 객체
- Fake : 단순한 형태로 동일한 기능은 수행한, 프로덕션에서 쓰기에는 부족한 객체(ex. FakeRepository)
- Stub : 테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체 (상태검증 - State Verification)
- Spy : Stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체, 일부는 실제 객체처럼 동작시키고 일부만 Stubbing할 수 있다.
- Mock : 행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체 (행위 검증 - Behavior Verification)
- 잘 모르는 기능, 라이브러리, 프레임워크를 학습하기 위해 작성하는 테스트
- 여러 테스트 케이스를 스스로 정의하고 검증하는 과정을 통해 보다 구체적인 동작과 기능을 학습할 수 있다.
- 관련 문서만 읽는 것보다 훨씬 재미있게 학습할 수 있다.