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

한빛출판네트워크

IT/모바일

Behavior Driven Development Using Ruby (Part 3) - (3)

한빛미디어

|

2007-12-21

|

by HANBIT

8,073

제공 : 한빛 네트워크
저자 : Gregory Brown
역자 : 노재현
원문 : Behavior Driven Development Using Ruby (Part 3)

커스텀 매처(Matcher)를 이용하여 예제 구성하기

코드내에 있는 영역중에서 잠재적으로 문제가 될 수 있는 영역을 쉽게 찾아내는 방법은 작성한 스펙에 의해서 실행되지 않는 영역을 찾아내는 것이다. RCov라고 불리는 툴은 바로 이런 용도로 사용되는 코드 커버리지 툴이다. 이 툴은 Test::Unit과도 사용될 수 있지만, RSpec에서 사용하는 것도 간단하다.

여기에 Dots 게임 코드에서 사용되는 기본적인 Rakefile이 있다.
require "rake"
require "spec/rake/spectask"

desc "Run all examples" 
Spec::Rake::SpecTask.new("examples") do |t|
  t.spec_files = FileList["spec/*_spec.rb"]
end          

desc "Run all examples with RCov" 
Spec::Rake::SpecTask.new("examples_with_rcov") do |t|
  t.spec_files = FileList["spec/*_spec.rb"]
  t.rcov = true
  t.rcov_opts = ["--exclude", "spec"]
end
이제 rake examples_with_rcov 라는 명령을 실행했을때 다음과 같은 멋있는 HTML 결과를 볼 수 있다.


[그림 1]

결과를 보면 어떤 코드가 BDD가 적용되었는지 안되었는지를 쉽게 알 수 있다. 더 좋은 점은 RCov는 줄 단위로 BDD 적용여부를 보여준다는 것이다. 다음 빨간색으로 하이라이트 된 줄은 BDD가 적용되지 않은 곳이다.


[그림 2]

인터페이스의 구현중에서 다음이 스펙을 적용하기에 가장 쉬운 방법이라고 생각된다. 다음을 보자. 이 정도면 커버리지 테스트를 해 보기에 충분할 것이다.
describe "An interface" do

  it "should prompt for players" 

  it "should prompt for grid size" 

  it "should be able to update board display" 

  it "should display a score board" do
    game = mock("game")
    players = %w[Greg Pete Paul] 
    game.should_receive(:players).and_return(players)
    players.each do |p|
      game.should_receive(:score).with(p).and_return(0)
    end 

    @interface.score_board(game).should == " Greg: 0 Pete: 0 Paul: 0"    
  end

  it "should prompt for a players move" 

end
여기서는 가짜 오브젝트를 이용해서 진짜 Dots::Game 오브젝트를 넘기지는 않지만, 이 예제만으로도 코드가 제대로 작동하는지를 파악하는데는 부족함이 없을 것이다.


[그림 3]

작은 수정으로 커버리지 테스트의 결과가 눈에 띄게 달라진 걸 볼 수 있다.


[그림 4]

RCov를 이용하면 얼마나 코드가 BDD 되었는지를 알 수는 있지만 이것만 가지고는 작성된 스펙이 질적으로 얼마나 좋은지를 가늠할 수 있는 척도가 되지는 않는다. 이제 스펙을 좀 더 향상 시킬 수 있는 방법에 대해서 살펴보도록 하겠다.

Heckle을 이용해서 좋지 않은 스펙 찾아내기

Heckle은 코드에 대한 에러를 유발시키는 동작을 해서 스펙에 문제점을 찾아내는 방식으로 동작을 한다. 물론 이 방법이 새롭게 알려진 방법은 아니지만 잘 보면 흥미로운 것을 알 수 있다. 여기서 가정하고 있는 것은 작성된 코드가 변경되었을때 단 실패가 발생하지 않는다면 그건 곧 아무것도 하지 않는 코드이거나 스펙이 완벽하지 않다는 것을 나타낸다.

spec 명령어는 Heckle과 같이 연동되도록 설치되게 되는데, 여기에 모듈이나 함수의 이름을 입력으로 주면 Heckle에게 작성한 스펙을 공격해 볼 수 있도록 하고 있다. 다음 샘플을 한 번 보도록 하자.
$ spec spec/game_spec.rb -H Dots::Game#start
.........

Finished in 0.027817 seconds

9 examples, 0 failures

**********************************************************************
***  Dots::Game#start loaded with 2 possible mutations
**********************************************************************

2 mutations remaining...
1 mutations remaining...

The following mutations didn"t cause test failures:

def start
  @players = interface.get_players
  @turn = -8
  @score = Hash.new(0)
  rows, cols = interface.get_grid_size
  @grid = Dots::Grid.new(rows, cols)
  interface.update_display(self)
end
Here"s the original code: 
def start
  @players = interface.get_players
  @turn = 0    
  @score = Hash.new(0)
  rows,cols = interface.get_grid_size 
  @grid = Dots::Grid.new(rows,cols)
  interface.update_display(self)  
end
Heckle을 통해서 알게 된 건 trun 변수가 0에서 시작해야 한다는 점을 우리가 명시해 주지 않고 있다는 것이다. 물론 지금 당장은 trun 변수가 0을 초기값으로 같지 않는다고 해도 게임이 작동하는데는 아무런 지장이 없다. 하지만 초기값이 0이 아니라는 사실이 필자에게는 조금은 놀랍게 느껴졌다. 간단한 스펙의 작성으로 이런 모호함을 해결할 수 있다.
describe "A newly started game" do

  # ...

  it "should start at turn 0" do
    @game.turn.should == 0
  end   

  # ...
end
이제 Game#start에 대해서 Heckle을 실행하면 결과는 "no mutants"라고 나오게 된다.
$ spec spec/game_spec.rb -H Dots::Game#start
..........

Finished in 0.029037 seconds

10 examples, 0 failures

**********************************************************************
***  Dots::Game#start loaded with 2 possible mutations
**********************************************************************

2 mutations remaining...
1 mutations remaining...
No mutants survived. Cool!
이런 Heckle과 같은 툴을 이용하는 것이 잠재적인 에러를 찾아내는데 도움이 된다고 생각은 하고 있지만, 필자 생각에는 이런 툴에 의지하고 스펙을 작성할때 집중해서 여러가지를 살펴보지 않는 것은 좋은 태도가 아니라고 생각한다. 물론 결과적으로 우리의 개발에 많은 도움이 될 것이다.

그리고 물론 RCov와 Heckle이 RSpec과만 사용될 수 있는 것은 아니다. Test::Unit과도 아주 잘 작동한다. 또 이런 툴들이 여러분이 코드의 상호작용적인 측면에 좀 더 신경쓰고 있을때도 도움이 되겠지만, 결과적으로는 BDD를 이용해서 프로젝트를 진행할때 잠재적인 문제점을 발견하는데 더 유용하게 사용될 수 있을 것이다.


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

최근 본 책0