Search

예제 상황으로 배우는 TDD

Tags

개요

본 포스팅은 Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트을 정리한 내용입니다.

1. 테스트가 왜 중요한가?

테스트가 왜 중요한지 상황을 가정해보겠습니다.
현재 프로젝트는 어떻게든 잘 돌아가는 레거시 프로젝트입니다.
하지만 서비스는 꾸준하게 성장하고 있습니다.
따라서 인력을 두 배 투입 했는데 개발 속도는 두 배가 되지 않았습니다.
알고보니 팀원들 사이에 배포하기가 무섭다 라는 고민이 있었습니다.
 왜 배포하기 무서워 했을까요?
잘 동작하던 기능이 갑자기 동작하지 않는 회귀 버그 (Regression)이 생길 수 있기 때문입니다.
따라서 회귀버그에 대처할 수 있는 테스트 자동화 (TDD) 를 도입하고자 합니다.
 TDD 도입이 만능일까요?
TDD를 도입해도 문제가 발생할 수 있습니다.
회사는 가시적인 성과를 내야 합니다. 하지만 테스트는 가시적인 성과를 내는 것이 아닌 안정화를 위한 작업입니다. 따라서 회사는 가시적인 성과를 위해 커버리지의 증가를 목표로 합니다.
커버리지를 높이기 위해 간단한 코드에도 테스트를 넣기 시작했습니다.
(당연한 것에도 테스트가 필요한지는 의문입니다)
또한, 요령없이 커버리지를 위해 작성한 테스트 코드는 비효율적입니다.
예를 들어, 모키토나 각종 의존성 주입을 통해 테스트를 진행한다면 테스트 하나를 위해 해야되는 (1) 준비 과정이 너무 많습니다.
데이터 베이스 까지 연동해서 테스트한다면 스프링 부트를 띄우고 의존성을 추적하고 테스트 해야되니 (2) 엄청 많은 시간이 소요됩니다.
또한 어제는 성공하고 오늘은 실패하는 (3) 비 결정적인 테스트도 존재합니다.
 앞선 상황의 문제점은 다음과 같습니다!
무작정 테스트를 작성하는 것이 TDD가 아닙니다.
레거시에 테스트를 넣으려면 코드 개선이 필요합니다. 회귀 방지에만 초점을 맞추는 것이 아닌 유연한 설계를 해야됩니다.
유연한 설계란 테스트를 쉽게 만들어주고, 테스트를 비 결정적이게 만들어줍니다.
또한 본인의 코드에 테스트를 넣는 방법을 알아야 합니다. 여기서 핵심은 자연스럽게 넣는 방법을 알아야 합니다.
프로젝트가 스프링이나 JPA에 의존되는 상황이라면 자연스럽게 넣기는 어렵습니다. (테스트와 설계는 긴밀한 관계를 유지하고 있습니다)
 해결 방법은 다음과 같습니다!
커버리지에 집착하면 안됩니다.
커버리지는 테스트가 얼마나 촘촘하게 짜여 있는지 평가합니다. 하지만 테스트를 추가했을 때 얻는 효용성 또한 생각해야 합니다.
또한, Mock, jUnit에 너무 의존하면 안됩니다.

2. 지향해야 하는 개발 방식

전통적인 서비스 성장 방식은 다음과 같습니다.
초기의 서비스를 소형차라고 하겠습니다.
차세대 서비스 개발은 서비스를 아예 새로 개발하는 것입니다. 이는 소형차를 중형차로 바꾸는 과정입니다.
중형차 단계에서 사용자가 몰려든다면 대형차로 바꾸는데 까지는 상당한 시간이 걸리며 이 과정 속에서 프로젝트가 중단될 가능성이 있습니다.
이러한 성장 방식은 끝이 어딘지 모릅니다.
회귀 버그 만을 신경쓰는 것은 자동차 부품들이 잘 작동 하는지 테스트 하는 것에 그칩니다.
하지만 우리가 지향해야 될 방식테스트와 확장성을 동시에 지닌 서비스의 성장 방식입니다.
 핵심은 다음과 같습니다.
서비스를 기차라고 가정해본다면, 사용자가 늘어나면 후미에 후차를 추가하면 됩니다.
서비스를 확장한다면 기능을 추가하고 테스트를 돌려보면 됩니다.