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

한빛출판네트워크

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

IT/모바일

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

한빛미디어

|

2007-12-20

|

by HANBIT

9,351

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

여러 문맥하에서의 Behavior 공유

코딩을 하다보면 기반이 되는 설정을 여러 문맥에서 조금씩 값만 바꿔서 사용되는 것을 볼 수 있다. 마찬가지로 특정 Behavior 또한 오브젝트 내의 여러 문맥에서 사용될 수 있다.

우리의 작은 게임에 있는 Dots::Box 클래스를 보면 문맥상에서 여러가지 패턴 들을 볼 수가 있다.
describe "A dots box" do   

  before :each do
    @box = Dots::Box.new 
  end

  it "should have 4 edges" do
    @box.edges.size.should == 4
  end

  directions do |dir|
    it "should have an #{dir} edge" do
      @box.edges[dir].should_not be_nil
    end 

    it "#{dir} edge should be :not_drawn by default" do
      @box.edges[dir].should == :not_drawn  
    end   

    it "#{dir} edge should be :drawn when draw_edge(#{dir.inspect}) is called" do
      @box.draw_edge(dir)
      @box.edges[dir].should == :drawn
    end
  end       

  it "should return nil for owner() by default" do
    @box.owner.should be_nil
  end

end  

describe "An incomplete dots box" do

  before :each do
    @box = Dots::Box.new   
  end   

  it "should return false for completed?" do
    @box.should_not be_completed
  end

  it "should not allow an owner to be set" do
    lambda { @box.owner = "Gregory" }.should raise_error(Dots::BoxIncompleteError)
  end

end  

describe "A completed dots box" do

  before :each do
    @box = Dots::Box.new
    directions { |dir| @box.draw_edge(dir) }
  end    

  it "should return true for completed?" do
    @box.should be_completed
  end 

  it "should allow an owner to be set" do
    @box.owner = "Gregory" 
    @box.owner.should == "Gregory" 
  end     

  it "should not allow an owner to be set more than once" do
    @box.owner = "Gregory" 
    lambda { @box.owner = "Joe" }.should raise_error(Dots::BoxOwnerAlreadySetError)
  end

end                               

describe "A positioned dots box at (0,0)" do

  require "set"                  

  before :each do
    @box = Dots::Box[0,0]    
  end  

  it "should have generated line coordinate tuples by compass direction" do
    @box.lines.should == lines   
  end  

  lines.invert.merge(Set[[10,1],[10,2]] => false).each do |edge, dir|

    it "should give #{dir.inspect} for edge?(#{edge.inspect})" do
       @box.edge?(edge).should == dir
    end

  end   

end
각 문맥에서 비슷한 설정을 하고 있는 것을 볼 수 있는데, 여기 "dots box" 문맥에 있는 대부분의 Behavior 들은 우리가 만들 모든 박스들에서 체크되어야 하는 Behavior 들이다. RSpec은 공유 Behavior 에 대한 기능을 지원하고 있다. 다음을 보면 알 수 있듯이 여기서 설정들과 예제를 여러 문맥에서 공유해서 사용할 수 있다. 위에 있는 코드를 다음과 같이 리팩토링을 해보았다.
describe "A dots box", :shared => true do   

  before :each do
    @box = Dots::Box.new 
  end

  it "should have 4 edges" do
    @box.edges.size.should == 4
  end

  directions do |dir|
    it "should have an #{dir} edge" do
      @box.edges[dir].should_not be_nil
    end    
  end       

  it "should return nil for owner() by default" do
    @box.owner.should be_nil
  end

end  

describe "An incomplete dots box" do

  it_should_behave_like "A dots box" 

  directions do |dir|

    it "#{dir} edge should be :not_drawn by default" do
      @box.edges[dir].should == :not_drawn  
    end

    it "#{dir} edge should be :drawn when draw_edge(#{dir.inspect}) is called" do
      @box.draw_edge(dir)
      @box.edges[dir].should == :drawn
    end        

  end

  it "should return false for completed?" do
    @box.should_not be_completed
  end

  it "should not allow an owner to be set" do
    lambda { @box.owner = "Gregory" }.should raise_error(Dots::BoxIncompleteError)
  end

end  

describe "A completed dots box" do

  it_should_behave_like "A dots box" 

  before :each do
    directions { |dir| @box.draw_edge(dir) }
  end    

  # ... examples unchanged

end                                

describe "A positioned dots box at (0,0)" do

  require "set" 

  it_should_behave_like "A dots box"                 

  before :each do
    @box = Dots::Box[0,0]    
  end  

  # ... examples unchanged 

end
위 코드를 잘 보면 여기서 before :each 콜을 재귀적으로 자유롭게 사용하고 있는 것을 볼 수 있다. "A completed dots box"에서 ("A dots box") 문맥 안에 있는 @box 오브젝트에 간단히 수정을 가해주는 반면 "A positioned dots box at (0,0)"는 전체 오브젝트를 대체시켰다. 이 기능은 실로 아주 유용하다. 여기선 다른 오브젝트를 다루고 있지만 실제로는 같은 변수 이름을 공유하기 때문에 Dots::Box[0,0]으로 생성된 것과 Dots::Box.new로 생성된 것이 같은 동작을 할 것이라는 것을 확신할 수 있다.

spec docs의 명령을 실행해 보면 각 문맥이 공유 Behavior를 이용해서 정상적으로 검증작업을 하는 것을 볼 수 있다.
$ spec spec/box_spec.rb -f s

An incomplete dots box
- should have 4 edges
- should have an north edge
- should have an south edge
- should have an east edge
- should have an west edge
- should return nil for owner() by default
- should return false for completed?
- should not allow an owner to be set
- north edge should be :not_drawn by default
- north edge should be :drawn when draw_edge(:north) is called
- south edge should be :not_drawn by default
- south edge should be :drawn when draw_edge(:south) is called
- east edge should be :not_drawn by default
- east edge should be :drawn when draw_edge(:east) is called
- west edge should be :not_drawn by default
- west edge should be :drawn when draw_edge(:west) is called

A completed dots box
- should have 4 edges
- should have an north edge
- should have an south edge
- should have an east edge
- should have an west edge
- should return nil for owner() by default
- should return true for completed?
- should allow an owner to be set
- should not allow an owner to be set more than once

A positioned dots box at (0,0)
- should have 4 edges
- should have an north edge
- should have an south edge
- should have an east edge
- should have an west edge
- should return nil for owner() by default
- should have generated line coordinate tuples by compass direction
- should give :north for edge?(#)
- should give false for edge?(#)
- should give :south for edge?(#)
- should give :east for edge?(#)
- should give :west for edge?(#)
이런 기능이 코드를 좀 더 DRY하게 만들어 줄 뿐만 아니라 여러 문맥에서 공유되는 Behavior 들이 정확하게 검증된다는 것을 알 수 있다. 또한 주어진 문맥에 여러 공유 Behavior 들을 포함할 수 있을 뿐 아니라 공유 Behavior에 공유 Behavior를 포함하는 것도 가능하기 때문에 여러가지 방면으로 확장해서 사용할 수 있다.


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

최근 본 상품0