brunch

You can make anything
by writing

C.S.Lewis

by 최창규 May 15. 2018

카카오헤어샵의 TDD

Write tests. Not too many.

TDD(Test Driven Development)는 이제 트렌드가 아닌 필수가 됐습니다. 우리는 몇 가지 규칙을 정해서 프로젝트에 TDD를 적용했습니다.



깨지는 테스트 -> 성공 테스트 -> 리팩터링을 반복하자.

먼저 깨지는(Fail) 테스트를 작성하고 그런 다음에 SUT(System under test)의 소스 코드가 테스트를 통과(Success)하게 수정합니다. 그리고 리팩터링을 시작합니다.

위 과정은 TDD의 가장 기본이 되는 프로세스입니다. 그래서 우리는 위 프로세스를 따르고 있습니다. 



Integration Tests 중심으로 작성하자.

개발자들이 할 수 있는 테스트는 Mock을 이용한 Unit Tests와 전체 로직을 테스트하는 Integration Tests가 있습니다. 우리는 Integration Tests 중심으로 작성했습니다. 그 이유는 비즈니스 로직이 단순히 DB에 CRUD 하는 것이 대부분이었고, 프로젝트 일정이 한정적이었기 때문입니다. 물론 둘 다 작성하는 개발자도 있었지만, 직접 DB에 CRUD를 해 보기를 권장했었습니다.



데이터가 없는 DB에서 테스트 하자.

Integration Tests를 개발 DB에서 돌리게 되면 간혹 Production 환경에서 잘못되는 경우가 있습니다. 왜냐하면 Test가 개발 DB의 데이터에 맞게 작성되면 Production 환경에서는 해당 데이터가 없을 수도 있기 때문입니다. 그래서 테스트 케이스는 데이터가 없는 Memory DB에서 돌려야 합니다. 그렇지 않으면 낭패를 볼 수도 있습니다.

그러기 위해서 테스트에 필요한 데이터는 반드시 @Test 블록 안에서 직접 구현해야 합니다. 카카오헤어샵에서 만든 아래 테스트 케이스의 예제를 보면 이해가 쉬울 것입니다.

        // given
        Shop shop = TestDataCreator.dummy(Shop.class);
        shopRepository.save(shop);

        Product product = TestDataCreator.dummy(Product.class);
        product.setShop(shop);
        productRepository.save(product);
        ...

         // when
        List<Styler> result = sut.findByProductOrderDisplayOrder(product.getId(), shop.getId());

         // then
        assertThat(result, hasSize(2));        

위 소스 코드에서 보는 바와 같이 @Test 에 필요한 Domain 객체들은 그 안에서 생성했습니다. 그래야 개발 DB이든, Production DB이든 정상적으로 동작하기 때문입니다. 도메인 객체 생성에 사용한 TestDataCreator는 https://github.com/cg4jins/JPATestDataCreator를 참고하세요.           

       


자동화 테스트 환경을 구축하자.

보통 개발자들이 현재 만들고 있는 소스 코드는 잘 테스트합니다. 그러나 프로그램은 다른 개발자가 수정한 부분 때문에 내 테스트 케이스가 깨지기도 하고, 아니면 본인이 수정한 다른 소스 코드 때문에 테스트가 깨지기도 합니다. 깨진 테스트는 곧 시스템의 버그로 나타납니다. 그래서 자동화된 테스트는 반드시 필요합니다.

우리는 CI(Continuous Integration) 프로그램인 Jenkins(https://jenkins.io/)를 설치해서 사용했습니다. Jenkins Job으로 git push가 될 때마다 테스트를 자동으로 수행해서 실패할 경우 Mail로 알리도록 했습니다. 그렇게 했더니 다른 개발자가 수정한 소스 코드 때문에 테스트가 깨지더라도 빠르게 알아챌 수 있게 되어 시스템 버그를 줄일 수 있게 되었습니다.



Test를 도와주는 라이브러리

Hamcrest(http://hamcrest.org/JavaHamcrest/)는 가독성 있는 테스트 코드를 작성할 수 있도록 도와줍니다. 특히 is()는 다재다능합니다. 

assertThat(result,  is(notNullValue()));
assertThat(result,  is("Hello"));


RestAssured(http://rest-assured.io/)는 Restful api를 쉽게 테스트할 수 있는 Java DSL 툴입니다. 

when().             
    get("/lotto/{id}", 5).     
then().             
    statusCode(200).             
    body("lotto.lottoId", equalTo(5),                   
               "lotto.winners.winnerId", containsOnly(23, 54));



정리

Microsoft의 조사에 따르면 TDD를 하면 15~35% 개발 시간이 증가하고, 버그는 40~90% 줄어들었다고 합니다. 정말 엄청난 마법이 아닐 수 없습니다. 다행히도 카카오헤어샵 개발자들은 모두 TDD의 마법을 경험한 사람들입니다. 그래서 프로젝트 초창기에 도입에 이견이 없었습니다. 아직 프로젝트에 TDD를 적용하지 못하신 분들은 서두르세요. 버그가 40~90% 줄어드는 마법입니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari