TDD 시작해보기

uchan·2023년 4월 3일
0

배경

프로젝트를 받고 기획자 또는 디자이너와 얘기를 한 뒤 개발을 할 때 다음과 같은 순서로 작업하였다.

예를 들어, 메인 페이지에서 쇼핑 아이템 목록을 보여주기 위한 API 개발할 때
1. 프론트 개발자와 API 요청 및 응답 인터페이스를 설계한다.
2. MVC 패턴에 맞춰 컨트롤러 및 뷰를 제작한다.
3. 로컬 개발환경에서 기대하는 동작이 이루어지는지 확인한다.
4. 테스트 코드를 작성한다.

테스트 코드 작성 중 "과연 이 테스트가 내가 생각하는 거만큼 충분히 커버를 해줄까? 어쩌면 쓸데없는 테스트를 만들고 있는게 아닐까?" 의문을 갖게 되었다. 어디까지 테스트를 작성하면 될 지, 좋은 테스트는 어떻게 만드는지 방법을 찾다 TDD 방법론 도입을 고민하게 되었다.

TDD

TDD 를 정리하면 다음과 같다.
1. RED: 테스트를 먼저 작성한다. 당연히 해당 테스트는 통과를 못한다.
2. GREEN: 작성한 테스트가 통과하기 위해 코드를 작성한다. 이때 테스트 통과만을 고려하며, 코드를 잘 짜려고 애쓰지 말자.
3. REFACTOR: 테스트를 통과했다면 작성한 코드를 이쁘게 다듬어주자.

TL;DR 워낙 유명한 방법론이고 간단해서 더이상 설명할 필요도 없을 거 같다.

근데 테스트는 어떻게 작성할까?

사실 TDD 가 가장 어렵게 느껴졌던 건 바로 RED 단계 때문이다. 테스트를 먼저 작성하라는데 뭐부터 어떻게 작성해야 될 지 막막하다. 뭔가 꿀팁이 없을까?...

문서화를 먼저해보자

동료로부터 좋은 방법을 배웠다. 바로 RED 단계 전 문서화를 먼저해보라는 것이다. 기획자 및 디자이너로부터 받은 내용을 토대로 스펙(체크리스트)를 만들어 보는 것이다.

scenariogivenwhenthen
유저가 로그인하지 않으면 아무것도 보여주지 않는다X인덱스 API 를 요청한다404를 반환한다
유저가 로그인하면 쇼핑 아이템 목록을 반환한다최근 모자를 구입한 유저가 로그인을 한다인덱스 API 를 요청한다200 및 모자 관련 아이템 리스트를 반환한다
...최근 옷을 구입한 유저가 로그인을 한다인덱스 API 를 요청한다200 및 옷 위주의 아이템 리스트를 반환한다

위 문서를 보니 기능을 한 눈에 파악하는데 쉽고 테스트 및 코드의 방향성이 보인다.

시나리오를 기준으로 나누어 코드를 작성해보자

RED 단계

# ruby 코드

describe '#Index API' do
	context '유저가 로그인하지 않았을 때' do
    	it '404 코드를 반환한다.' do
        	...
        end
    end
    
    context '유저가 로그인하였을 때' do
    	context '최근 모자를 구입했다면' do
        	it '200 코드와 모자 리스트를 반환한다.' do
            	...
            end
        end
        
        context '최근 옷을 구입했다면' do
        	it '200 코드와 옷 리스트를 반환한다.' do
            	...
            end
        end
    end
end

GREEN

class ItemsController < BaseController
	def index
    	# index action 에서 유저가 로그인하지 않으면 404
        return 404 if current_user.nil?
        
        # 유저가 최근 구매한 아이템
        recent_item = user.recent_items.first
        
        # 만약 최근 구매한 아이템이 옷이라면
        if recent_item.clothes? # enum 이 적용되어 자동으로 만들어진 메서드 사용
        	...
        end
        
        # 이하 생략
    end
end

REFACTOR

class ItemsController < BaseController
	# before_action 콜백으로 유저 로그인 여부 처리하자
    before_action :authenticated_user  # 요건 자주쓰이니 최상위 컨트롤러(BaseController) 에 만들자
    
	def index
    	# 가독성을 위해 if 보다는 case-when 으로
        case user.recent_items.first
        when 'clothes'
        	...
        when 'hat'
        	...
    end
end

해당 글에서는 간단한 예시라 쉽게 작성하였지만 실제 프로젝트에서는 까다로운 로직 및 자주 일어나는 변경 등의 이유로 스펙(문서화)을 작성하기 매우 까다로울 것이다. 그래도 한번 만들어놓으면 이후 QA 까지 한방에 해결할 수 있으니 얼마나 매력적인가.. 이후 나에게 맞는 문서 작성방법을 연구하여 최적의 방법을 만든다면 강력한 무기가 될 거 같다.

reference

0개의 댓글