메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

Cookin" with Ruby on Rails - More Designing for Testability(3)

한빛미디어

|

2007-10-15

|

by HANBIT

11,127

제공 : 한빛 네트워크
저자 : Bill Walton
역자 : 김탁용
원문 : Cookin" with Ruby on Rails - More Designing for Testability

[이전 기사 보기]
Cookin" with Ruby on Rails - More Designing for Testability(1)
Cookin" with Ruby on Rails - More Designing for Testability(2)

Paul: 알아듣겠어요. 그걸 생각해볼 수 있게 해줘서 고마워요. 사실, 우리가 단위 테스트에서 했던 많은 걸 또 하고 있단 생각을 하고 있었어요. 데이터를 바꾸고 실제로 그 데이터가 데이터베이스에서 바뀌었는지 확인하려고 다시 가져오고. 그러나 이렇게 생각해봤으니, 아마 접근하는데 더 좋은 방법이 있을 거예요. 이건 어떤 것 같아요?
def test_update
   post :update, :id => @first_id
   assert_response :redirect
   assert_redirected_to :action => "show", :id => @first_id
   post :update, :id => @first_id, :name => ""
   assert_template "edit"
end
CB: 잘 파악한 것 같은데요. 테스트 케이스를 실행하고 어떻게 되는지 보죠.

Paul: 좋아요.
ruby testfunctionalcategory_controller_test.rb

[그림 26]

어떻게 생각해요? 잘 됐나요?

Paul: Rendering with nil? 대체 뭔 소리람? 컨트롤러 메소드가 edit 템플릿을 렌더링 하려고 했는데 update가 성공하지 않았다는 건가요? 잘 모르겠어요.

CB: 한 발 물러서서 우리가 여기서 정말로 테스트하고 있는 것에 대해 생각해봐요. 보고 있는 게 컨트롤러 로직 테스트인가요? 우리는 create가 성공적일 때 애플리케이션이 가는 경로를 테스트하고 있는 거죠. 뭐가 create를 실패시킨 거죠? 유효성 체크라고요! 유효성 체크가 실패하면 에러 메시지를 만들고 렌더링되었던 마지막 페이지에 그 메시지를 보여줘요. 하지만 내부 프로세스는 한번에 그걸 처리하니 다소 거칠긴 해도 가장 명백한 방법으로 테스트해보죠. 애플리케이션을 다시 실행시키고 테스트 메소드가 한 것과 같은 걸 해보는 거예요. "Show all categories" 링크를 클릭하고, 카테고리 이름을 클릭, 그리고 에디트를 클릭해봐요, 그 다음에 이름을 입력하고 버튼을 눌러요.


[그림 27]

CB: URL 보여요? 아직 update 메소드 안에 있네요. "rendering with " failure은 update 템플릿이 없기 때문이라는 게 설명되네요. 하지만 Rails가 요청을 처리하고 방문자에게 에러 메시지와 함께 방문자를 edit page로 보내는 건 명백해요. 그럼, test_update 메소드에 있는 이 줄을..
assert_template "edit"
이렇게 바꿀게요
assert_response :redirect
그리고 테스트 케이스를 다시 실행하면..


[그림 28]

Paul: 좋아! 남은 건 test_destory 메소드뿐이군요. 다시 한 번 보죠.


[그림 29]

Paul: 아시다시피, Exception 핸들링 assertion을 다소 이해하고 있고, 삭제되지 말아야 할 레코드를 삭제하는 충돌로부터 우리 코드와 단위 테스트 둘 다 막는 게 더 좋다고 한 걸 기억하거든요. 더 손보지 않아도 되겠네요. assert_nothing_raised가 find에서 실패한다면, 테스트 케이스는 테스트 데이터의 문제를 나타내는 failure와 함께 끝날 거고요. Find가 성공한다면, 레코드를 삭제하는데 문제가 없을 거예요. 그리고 실제로 테이블에서 지워졌는지를 체크하죠. 다소 단위 테스트와 중복된 감이 있지만 문제는 없어요.

CB: 좋아요, 그럼 조리법 컨트롤러 테스트들을 할 준비도 됐나요?

Paul: 물론이죠. 지금 한 것들이랑 매우 비슷할 거 같은데요. 여기, 고친 category_contoller_test.rb 파일이요.


[그림 30]

CB: 예, 잘된 거 같군요. recipe_controller_test를 하기 전에 마지막으로 실행시켜보고 여기까지 잘해왔는지 확인해봅시다.
ruby testfunctionalcategory_controller_test.rb

[그림 31]

잘 되는군요! category_controller_test를 옮겨도 될 거 같아요. 앞으로 가서 전에 했던 :first 픽스쳐 레퍼런스를 고칩시다. setup 메소드에서..
@first_id = recipies(:first)
이렇게 바꿔요.
@first_id = recipes(:one)
그리고 조리법들은 제목이 있어야 하고 작업하면서 유효성 체크도 category로 넣었으니까, 앞의 test_create 메소드도 에러를 피하도록 바꾸죠. 이거를..
post :create, :recipe => {}
이렇게요.
post :create, :recipe => {:title => "new recipe", :category_id => 1}
그럼 이제 조리법 컨트롤러를 실행시켜서 어떻게 되는지 볼까요?
ruby testfunctionalrecipe_controller_test.rb

[그림 32]

Paul: 시작이 좋은데요. ;-)

CB: 나도 동의해요, 폴 ;-) 작업이 필요한 곳에 변화를 주고 싶죠?

Paul: 그럼요. 다시 위에서 시작하려던 참이었어요. test_index 메소드는 괜찮아 보이고요. 카테고리 컨트롤러 테스트에서 test_verify_gets_are_safe 메소드를 복사해올게요.
def test_verify_gets_are_safe
   get :destroy
   assert_redirected_to :action => "list"
   get :create
   assert_redirected_to :action => "list"
   get :update
   assert_redirected_to :action => "list"  
end
조리법 컨트롤러의 list 메소드는 카테고리로 필터링 하느라 바꿔서, 카테고리 컨트롤러의 list메소드랑은 다르네요.


[그림 33]

여기 테스트 메소드를 강화시킬 필요가 있겠어요. 이게 지금 내용이에요.


[그림 34]

Paul: 이 테스트는 list 메소드의 첫 번째 분기를 살피기 위해 category_id 파리미터에 어떤 값도 전달하지 않아요. category_id를 전달해 여기 안에 두 번째 통과 단계를 두고, 같은 assertions들이 여전히 통과하는지 확인해야겠어요. 단지 올바른 레코드들이 리턴되는 지를 확인한다는 게 이해되지 않는군요. 특히 컨트롤러 테스트에서가 아니라면요. 그것에 대해 테스트한다면, 단위 테스트에서 해야 할 거예요. 어떻게 생각해요?

CB: 좋은 생각 같아요.

Paul: 좋아요. 그럼, test_list를 test_list_all_and_filtered로 바꾸겠어요
def test_list_all_and_filtered
   get :list
   assert_response :success
   assert_template "list"
   assert_not_nil assigns(:recipes)
   get :list, :category_id => "1"
   assert_response :success
   assert_template "list"
   assert_not_nil assigns(:recipes)
end
test_show와 test_new 메소드는 괜찮군요. 그런데 test_create는 카테고리 컨트롤러 테스트에서 해줬던 거랑 같은 처리를 해줘야겠어요. 그럼 test_create를 test_create_success_and_failure로 바꿀게요. 변수 이름들만 빼면 전에 한 것과 매우 비슷하네요. 조리법을 성공적으로 저장하려면 제목과 외래키가 꼭 필요하단 걸 잊으면 안돼요.
def test_create_success_and_failure
   num_recipes = Recipe.count
   post :create, :recipe => {:title => "new recipe", :category_id => 1}
   assert_response :redirect
   assert_redirected_to :action => "list"
   assert_not_nil flash[:notice]
   assert_equal num_recipes + 1, Recipe.count

   num_recipes = Recipe.count
   post :create, :recipe => {:title => ""}
   assert_response :success
   assert_template "new"
   assert_equal num_recipes, Recipe.count
end
test_update 메소드에서는, 유효하지 않은 업데이트가 에러를 만드는지를 확인해야 해요. 카테고리 컨트롤러에서 해줬던 것처럼요. 메소드 끝에 똑 같은 두 줄을 추가할게요,
post :update, :id => @first_id, :title => ""
assert :redirect
Test_destory 메소드에 넣어줄 것도 카테고리 컨트롤러에서도 같은 이유로 해줬던 거고요. 금방 끝낸 거 같네요.

CB: 훌륭해요, 폴. 한 거를 한번 봅시다.


[그림 35]

CB: 훌륭하군요! 테스트 케이스를 실행시켜서 결과를 보죠.
ruby testfunctionalrecipe_controller_test.rb

[그림 36]

CB: 자 그럼 이제. 가치가 있는 좋은 시간이었던 거 같아요. 당신은 어때요, 폴?

Paul: 어서 통합 테스트를 뛰어들고 싶으니, 제가 달려야겠네요. 고객들과 테스트 계획을 리뷰하는 회의를 갖고요.

CB: 당신도 알다시피, 통합 테스트 때는 보스를 데려와야 할 거라 생각했었거든요. 그가 꼭 함께 했으면 해요. 테스트 계획 모델을 통해 일하는 방법을 보일 기회를 당신한테 줄게요. 어때요?

Paul: 정말 흥미롭겠어요. 보스에게 가서 참여할 수 있는지 봐야겠어요. 다음 번엔 그를 데려올 수 있도록 최선을 다할게요. 잘 있어요, 친구.

끝.


저자 Bill Walton 은 소프트웨어 개발/프로젝트 매니지먼트 컨설턴트이자 사업자입니다.


역자 김탁용님은 연세대학교 컴퓨터과학과를 졸업하고 현재 대한항공 정보시스템실에서 근무하고 있습니다. 무엇인가 새로운 것을 만드는 일, 그로 인해 다른 사람들에게 도움이 되는 일에 관심이 많아 소프트웨어 개발을 계속 하고 있습니다.
TAG :
댓글 입력
자료실

최근 본 상품0