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

한빛출판네트워크

한빛랩스 - 지식에 가능성을 머지하다 / 강의 콘텐츠 무료로 수강하시고 피드백을 남겨주세요. ▶︎

IT/모바일

Cooking with Ruby on Rails - Designing for Testability(3)

한빛미디어

|

2007-08-30

|

by HANBIT

10,877

제공 : 한빛 네트워크
저자 : Bill Walton
역자 : 노재현
원문 : Cookin" with Ruby on Rails - Designing for Testability

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

CB : 이제 데이터를 좀 갖춰놨으니 테스트를 작성해 보자고. 카테고리 model을 먼저 보자고. 우선 category_test.rb 파일을 열고 기본적인 CRUD 기능을 테스트할 함수를 만들어 볼 거야. test_truth 함수를 지우고 카테고리 model의 기본적인 읽기와 업데이트 기능을 테스트 해 볼거야.
def test_read_and_update
 rec_retrieved = Category.find_by_name("beverages")
 assert_not_nil rec_retrieved
 rec_retrieved.name = "beverage"
 assert rec_retrieved.save
end
우선 함수 이름을 어떻게 지었는지 봐야해. Rails의 모든 테스트 함수 이름은 test_ 로 시작하게 되어 있어. 이제 테스트 케이스를 다시 실행해 보면
ruby testunitcategory_test.rb 

그림 22.

Paul : 또 에러네요? 고친것 같은데

CB : 이건 다른 에러야. 3번째 줄에 에러메시지 보여? "지우거나 업데이트 할 수 없다(cannot delete or update...)"라고 말하고 있어. 저번 에러는 추가하거나 업데이트 할 수 없다" 였는데 이상하지?. Rails가 테스트 함수를 실행할때 제일 처음하는 일이 테이블에 있는 모든 레코드를 삭제하고 테이블을 fixture에 있는 값으로 채우는 일이야. 지금은 각 카테고리에 조리법이 연결되어 있기때문에 MySQL이 삭제할 수 없다고 말하고 있는거야.

지난 번에도 이런 경험을 한 번 한 적이 있었잖아. 첫 시간에 조리법을 가지고 있는 카테고리를 삭제하려고 했을때 에러나던거 기억하고 있어? 이렇게 에러가 났었잖아(그림 33). 그 당시에는 해당 카테고리에 조리법이 연결되어 있는지를 확인한 후에 조리법이 있으면 아무것도 하지 않도록 임시로 수정했었잖아. 그 때는 나중에 이 상황을 어떻게 해결해야 할지 보자고 했었는데, 바로 그 때가 지금이 되버렸네?

문제를 두 가지로 나눠서 해결해 보자. 첫번째로 테스트를 할 때 어떻게 이 문제를 해결할지를 결정하는 것이야. 지금 상황으로서는 해당하는 recipes 테이블에 조리법이 있는 상황에서는 카테고리 fixture에서 아무 데이터도 로드할 수가 없어. 가장 간단한 방법은 recipes 테이블에 아무 데이터도 없도록 하는 거야. 조리법에 관한 테스트를 할때 테스트가 다 끝나고 나서 테이블을 싹 다 지워주는 거지. 내가 전에 setup과 teardown 함수에 대해서 설명해 줬던거 기억나? 두 함수가 테이스 케이스 파일에 있을 경우 매번 테스트 함수가 호출되기 전하고 후에 불린다고 했었잖아. 여기서는 teardown 함수를 이용해서 한 번 문제를 해결해보자고. recipe_test.rb 파일을 열고 다음을 추가하면
def teardown
 recipes = Recipe.find(:all)
 recipes.each do |this_recipe|
  this_recipe.destroy
 end
end
이제 recipe_test.rb 테스트를 다시 실행하고
ruby testunitrecipe_test.rb 

그림 23.

이제 teardown 함수가 제대로 테이블을 지웠는지 확인해 보자고.


그림 24.

CB : 이런. 실수. 우선 좋은 소식은 테스트에 에러가 없었던 걸로 봐서는 teardown 함수가 정상적으로 작동했다는 거야. 이번에 발생한 문제는 아직 얘기하지 않았던 건데. 이전에 Rails가 매번 테스트 함수를 실행하기 전에 fixture에서 데이터를 로딩해서 테이블에 넣는다고 했었잖아. 이런 동작을 하게 하는데 두 가지 방법이 있어. 하나는 Rails가 실제로 데이터를 매번 지우고 로딩하도록 하는거야. 하지만 이 방법은 테스트 함수가 많아지고 fixture가 많아 질 수록 정말 많은 시간이 소요될 수가 있어. 그래서 Rails가 또 다른 방법을 제시하고 있는데 그게 바로 트랜잭션(transaction) 기반의 접근 방법이야. 기본적으로 Rails는 첫번째 테스트 함수를 실행하기 전에 fixture에서 데이터를 모두 로딩하고 테스트 함수가 끝날때 트랜잭션 기능을 이용해서 테이블의 상태를 최초 데이터가 처음 로딩되었던 상태로 복귀시키는 것이지. 바로 이런 트랜잭션 방식이 기본 방식으로 설정되어 있고, 내가 이걸 바꾸는 걸 까먹어 버렸네. testtest_helper.rb 파일을 열고 다음의 라인을 바꿔보자고.
self.use_transactional_fixtures = true 
self.use_transactional_fixtures = false 
이제 조리법 테스트 케이스를 다시 실행해 보면 문제가 해결된 걸 알 수 있어.


그림 25.

데이터베이스를 보면


그림 26.

CB : 이제 recipes 테이블이 비어 있는걸 확인해 봤으니 카테고리 테스트를 다시 실행해 보자고.
ruby testunitcategory_test.rb 

그림 27.

Paul : 음 아직 완전히 다 테스트 한 것 같지 않아요. 몇가지 더 확인해 봐야 될 것 같은데요. 우선 Rails가 "beverages"를 "beverage"로 바꿨다고 했는데 아직 실제로 "beverage"라는 테이블이 있는지 확인하지 못했어요. 그리고 "beverages"라는 레코드가 이제 없다는 것도 확인해 봐야 될 것 같아요.

CB : Paul 자네가 테스터 역할에 잘 어울릴 줄 알고 있었다니까. 맞았어. 자 테스트를 추가해 보자고.
def test_read_and_update
 rec_retrieved = Category.find_by_name("beverages")
 assert_not_nil rec_retrieved
 rec_retrieved.name = "beverage"
 assert rec_retrieved.save
 changed_rec = Category.find_by_name("beverage")
 assert_not_nil changed_rec
 unwanted_rec = Category.find_by_name("beverages")
 assert_nil unwanted_rec
end
category_test.rb 테스트를 다시 실행해 보면


그림 28.

CB : 이제 읽고, 업데이트 하는 기능이 정상 작동한다는 걸 확인했고 이제 생성과 삭제 기능이 정상작동하는지 확인해 볼 차례네

Paul : 그런데 이미 fixture로 데이터를 채우고 teardown 함수로 데이터를 지우면서 테스트해보지 않았나요?

CB : 좋은 질문이야 Paul. 두 가지 방식으로 생각해 볼 수 있을 것 같아.

한쪽으론 read_and_update 함수로 데이터베이스에 데이터가 생성된 걸 볼 수 있었어. 왜냐면 데이터가 없었다면 아무것도 읽고 업데이트할게 없었을테니까. 그리고 조리법 테스트를 실행하고 나서 테이블을 보니 테이블이 비어 있던 걸 확인했었지.

다른 한쪽으론 생성과 삭제 기능을 위한 테스트 함수를 만들게 된 이유가 몇가지 있어. 첫 번째로 테스트 케이스를 보고 애플리케이션이 무엇을 하는지를 알기 위해서야. 내가 생성과 삭제에 대한 테스트 함수를 만들지 않으면 애플리케이션이 생성과 삭제를 하고 있다는 것을 항상 기억하고 있어야만 하지. 근데 내가 이제는 기억력이 그리 좋지 않은 나이이기도 하고. 두 번째로는 Unit 테스트가 model을 테스트하기 위한것인데 여기서 model을 확실하게 테스트 했으면 해. fixture 파일을 보면 알겠지만 model 그 자체에 대한 사용법은 전혀 나와있지 않아. 내가 내 기억력을 신뢰할 수 있고 Rails가 아주 잘 작동한다면 이 테스트 함수를 작성할 필요가 없겠지. 하지만 내가 테스트 역할에서 볼때 나의 SOP는 "보여줘", "믿지 말고" 라고 말하고 있어.

이 테스트는 간단하고 실행시간도 짧으니 category_test.rb 파일에 테스트 함수를 추가해 보겠어. 전에 읽고 업데이트 하는 테스트 함수하고 같은 방식으로 추가해 볼께
def test_create_and_destroy
 initial_rec_count = Category.count
 new_rec = Category.new
 new_rec.save
 assert_equal(initial_rec_count + 1, Category.count
 new_rec.destroy
 assert_equal(initial_rec_count, Category.count)
end
테스트 케이스를 다시 실행해 보면


그림 29.

CB : 자 이제 우리의 카테고리 모델이 정상작동하고 있는 걸 확신할 수가 있어. 이제 조리법 모델에도 같은 테스트 함수를 추가해 보자고. recipe_test.rb 파일을 열고 test_truth 함수를 다음의 함수로 바꿔보자고.
def test_read_and_update
 rec_retrieved = Recipe.find_by_title("pizza")
 assert_not_nil rec_retrieved
 rec_retrieved.title = "pie"
 assert rec_retrieved.save
 changed_rec = Recipe.find_by_title("pie")
 assert_not_nil changed_rec
 unwanted_rec = Recipe.find_by_title("pizza")
 assert_nil unwanted_rec
end

def test_create_and_destroy
 initial_rec_count = Recipe.count
 new_rec = Recipe.new
 new_rec.category_id = 1
 new_rec.save
 assert_equal(initial_rec_count + 1,Recipe.count
 new_rec.destroy
 assert_equal(initial_rec_count, Recipe.count)
end
조리법 테스트 케이스를 실행해 보면


그림 30.

잘 작동하는 것 같은데 어때 Paul?

Paul : 괜찮은 것 같은데요. 이제 우리가 찾은 버그들을 수정해도 괜찮을까요?

CB : 좋았어. 그럼 이제 우리가 만든 테스트를 이용해서 개발을 해보자고.


역자 노재현님은 어렸을 때부터 컴퓨터를 접하게 된 덕에 프로그래밍을 오랫동안 정겹게 하고 있는 프로그래머 입니다. 특히나 게임 및 OS 개발에 관심이 많으며, 심심할 때면 뭔가 새로운 프로그램을 만들어내는 것을 좋아합니다. 다음에서 웹 관련 개발을 한 후에 현재는 www.osguru.net이라는 OS관련 웹사이트를 운영하며 넥슨에서 게임 개발을 하고 있습니다.
* e-mail: wonbear@gmail.com
* homepage: http://www.oguru.net
TAG :
댓글 입력
자료실

최근 본 상품0