TDD
in Development on TDD
TDD의 계기
이번에 우리 회사의 신규 프로직트 카카오 워크
에 지원을 가게 되면서 이번 프로젝트는 TDD로 진행해보려고 한다.
내가 이 프로젝트에서 TDD를 진행하는 이유에는 두 가지가 있다. (사실 누구도 TDD를 하라고 시킨 사람은 없다 카카오는 그런 조직이니까)
첫 번째 이유는 실력있는 시니어 개발자분들과 함께하기 때문에 테스트코드를 짜고 코드리뷰를 받으면 더 성장할 수 있을 것이라는 확신이 생겼기 때문이다.
두 번째는 백엔드에서 내가 유일하게 막내 신입이기도 하고 해서 TDD로 개발해본 경험이 없기 때문에 신입의 TDD 도전기를 나중에 팀원들에게 공유해보는 것도 좋은 기회가 될 것이라고 생각했기 때문이다.
그래서 오늘은 아샬님의 TDD 강의를 보고 느낀 점을 적어보려고 한다.
Test Driven Development란
TDD는 테스트 주도 개발의 약자이다.
Test First Development라고도 불린다.
이 TDD는 아주 단순한 세 가지의 순서로 코드를 만든다.
실패
해결
개선
실패하는 테스트를 작성하고 통과시킨 후 코드를 개선한다.
이 과정을 계속해서 반복한다.
그럼 이러한 TDD는 말이 거창하지 사실상 테스트 코드를 먼저 작성하는 개발 방법론이다.
그래서 TDD의 산출물은 테스트코드이다.
이러한 테스트 코드는 증거물이 된다.
이 프로그램이 제대로 작동하는지에 대한 증거말이다.
BDD
이러한 테스트 코드를 작성하는 방법에는 마틴 파울러 아저씨의 BDD라고 불리는 방식이 사용된다.
Behavior Driven Development라고 불리우는 이 개발 방법론은 다음의 세 가지 과정을 갖는다.
Given
- 주어진 상황이다. 가령 테스트를 위한 상황을 가정하고 시작한다. e.q. 사용자가 추가되었다.
When
- 특정한 동작을 명시한다. e.q. 방금 추가된 사용자를 조회할 때
Then
- 동작이 제대로 작동했는지를 검증한다. 방금 추가된 사용자가 존재한다면 테스트 통과, 아니라면 실패
DDD
도매인 주도 설계의 줄임말로써 해당 내용은 내가 잘 몰라서 추후에 스터디해봐야할 것 같아서 패스.
DDD에서 중요한 내용은 단 하나.
UI Layer(HTML, HTTP API)가 무엇이든 같은 Application Layer(Service)를 사용한다는 점.
결국 코드의 재사용을 위한 구조를 갖는 것을 의미한다.
Test Double
Stunt Double이라는 용어가 있다.
실제 배우가 아닌 스턴트맨을 투입하는 것을 Stunt Double이라고 표현한다고 한다.
테스트에서도 마찬가지로 Test Double이라는 용어가 있는데 Mock Object, Fake Object, Test Spy 등으로 불리운다.
어쨌든 중요한 것은 테스트에 스턴트 맨을 투입한다는 점이 중요하다.
가령 Repository 인터페이스를 구현하는 RealRepository와 FakeRepository가 있다고 가정해보자.
FakeRepository는 가짜 데이터를 돌려주고 가짜로 영속성을 흉내내는 것이다.
이러한 것을 좀 쉽게 도와주는 것이 Mock Framework라고 불리우는 것들이다.
그 중에 스프링부트에서 밀어주는 것이 바로 Mockito이다.
아샬님의 테스트 스타일
도메인 테스트는 기본인데 레포지토리에 대한 테스트도 작성해야하는지 궁금할 수 있다.
일반적으로 Repository의 테스트는 잘 작성하지 않는 경우가 많지만 아샬님의 경우에는 Repository 테스트도 작성한다고 한다.
JPA의 경우 Entity Manager라는 것이 존재한다.
얘가 트랜잭션 관리를 하는데 테스트에 트랜잭셔널을 붙이면 실제로 커밋을 하지 않아서 DB를 타질 않는다.
그래서 트랜잭션 관리를 위해 레포지토리 테스트를 작성하게 되는데 그 경우 아래와 같이 작성한다고 한다.
@BeforeTransaction
=> Given / When
+
@Test
=> Then
그러면 이러한 테스트는 어쩌면 대부분이 학습 테스트일 수 있다. (어? 왜 안되지? 어? 왜 됐지?)
그래서 까딱 잘못하면 Spring Data JPA를 테스트하는 꼴이될 수 있다.
때문에 테스트를 위한 테스트를 작성하지 않도록 주의해야한다.
그러니 우리가 테스트 코드를 작성하는 본질, GOAL에 집중하자.
Step의 함정
테스트를 할 때 보통 단계를 나눠서 한다.
HTTP API를 테스트할 때 JSON을 돌려줄 것이다.
문제는 JSON을 테스트하게 되면 테스트가 깨지기 너무 쉽다. (JSON 리스트는 얼마든 쉽게 바뀔 수 있으니까)
Jackson을 테스트하지 말자
JSON이 아닌, DTO를 검증하자
이러면 테스트하는 대상이 바뀌게 된다.
그러니 Application Layer만 제대로 테스트하면 된다.
그래서 테스트를 만들 때 하나씩 테스트를 개발해야한다.
결론
Goal First
목표를 먼저 정하고 이대로 수행한다.
이 목표를 이루기 위해 Test를 작성한다.
그리고 테스트가 박살나는 것을 구경한다.
그리고 나서 Small Steps로 나눠서 하나씩 검사한다.
가장 중요한 것은 이 과정이 끝나고 반드시 리팩토링 과정을 거쳐야한다.
그러고 나서 리팩토링을 한다.
그 후 리팩토링을 하고,
리팩토링을 한다.
리팩토링이 끝나면 리팩토링을 하고..
…
X 1000000
끝.