인수 테스트를 이용한 개발 흐름
💡 가독성
- 가독성이 좋지 않으면 방치됨
- 변경 사항에 대해 수정이 어려움
- 중복 제거가 필요
중복 제거
- 메소드 분리
- CRUD 추상화
- Cucumber, JBehave와 같은 BDD 도구 사용
의도 드러내기
리팩토링하는 이유
- 테스트를 유지보수하기 좋은 상태로 만들기 위해
💡 인수 테스트 잘 작성하기
인수 조건을 테스트로 옮기기
Feature: 간략한 기능
Background: 시나리오 사전 조건
Scenario: 시나리오 제목
given: 사전조건
when: 발생해야 되는 이벤트
then: 사후조건
And: 앞선 내용에 추가적인 내용 기술
확인하는 방법?
1) 응답 코드로 확인
2) 조회 request 후 response 값에서 확인
중요한 로직이라면 2, 1번으로도 넘어갈 수 있게끔 구성
1+2도 쓸 수 있다~ 그러나 꼼꼼히 만들다가 루즈해지지 않도록 조심
인수 테스트 클래스
- Feature 기준으로 클래스 나눔
- Scenario 기준으로 메소드 나눔
- Feature 내부의 Scenario는 같은 테스트 픽스쳐를 공유
간단한 성공 케이스를 우선 작성
- 동작 가능한 간단한 케이스 먼저
- 실패하는 테스트를 지켜보기
- when - then - given 순서로 작성하기 (명확한 순서대로)
💡 TDD ! 어려워 !
규칙은 간단하지만 잘 하는지 모르겠음
대부분의 내용이 추상적임
인수 테스트 기반으로 TDD를 하면?
- 인수 테스트로 TDD로 개발할 방향을 지시
- 중간에 길을 잃더라도 인수 테스트를 기점으로 다시 찾기 쉬움
어떻게 인수 테스트에서 TDD 사이클로 가나?
단위 테스트
- 작은 코드 검증
- 빠르게 수행
- 격리된 방식으로 처리
Test Double
테스트 대상이 의존하는 객체를 협력 객체라고 하는데
이 때 협력 객체를 Test Double이라고 한다.
실제 객체 대신 사용되는 모든 종류의 객체애 대한 일반 용어
Stub
mockito
짜고 치기
A 메소드를 호출하면 B 응답이 나오는 것을 미리 정해둠
when().thenReturn() ~~~
Mock
mocking된 방식으로 만들어진 객체
mocking: 행위를 지정하고 테스트를 만드는게 아니라 협력 객체가 호출되는 횟수를 지정을 하고 호출되었는지 여부를 검증하는 방식
행위를 검증
Fake
다른 객체를 가지고 테스트를 만드는 것
dao -> db
fakeDao -> HashMap
협력 객체를 실제로 만들까 가짜로 만들까?
- 실제 객체를 사용하면 협력 객체의 행위를 협력 객체 스스로가 정의
- 가짜 객체를 사용하면 협력 객체의 행위를 테스트가 정의
테스트의 목적이 뚜렷하다면 가짜 객체
가짜 객체(테스트 더블)을 사용한다면
- 테스트 대상을 검증할 때 외부 요인(협력 객체)으로부터 철저히 격리
- 테스트가 협력 객체의 상세 구현을 알아야만 구현 가능 == 깨지기 쉬움
진짜 객체를 사용한다면
- 협력 객체의 상세 구현에 대해 알 필요 없음
- 협력 객체의 정상 동작 여부에 영향을 받음
그래서!
- TDD를 연습할 때는 실제 객체를 활용하는 것을 우선적으로
- 테스트 작성이 어렵거나 흐름이 이어지지 않는다면 테스트 더블을 활용하는 방법으로 접근
OutSide-In Tdd Inside-Out Tdd
💡 인수 테스트 기반 리팩토링
테스트 코드 - 프로덕션 코드를 다 짜고
불필요한 필드나 클래스를 발견하면
결국 테스트를 다 지우고 새로 짠다... 이게 맞아?
테스트를 먼저 수정한다면?
레거시 코드 리팩토링
- 인수 테스트를 작성해서 기존 구현된 기능을 보호
- 파악 가능한 부분부터 단위 테스트를 만들어 기능 검증
- 인수 테스트 보호 속에서 리팩토링
장점
- 인수 테스트 작성 후 리팩토링하면 사이드 이펙트에 대한 피드백을 바로 받을 수 있음
- 기능을 구현하다 꼬여도 인수 테스트 성공 시점으로 리셋 가능
- 안심하고 작은 단위로 메소드를 분리할 수 있음
팁
- 기존 코드를 수정하려 하지 말고 새로운 코드를 한 벌 더 만들어보기(스트랭글러 패턴)
💡 인증 기반 인수 테스트
RestAssured 기반의 테스트에서는 auth() 메소드를 통해 로그인과 데이터 요청을 한번에 받을 수 있다.