RE: スはスペックのス〜RSpecによるテスト駆動開発の実演

前回の続き(スはスペックのス〜RSpecによるテスト駆動開発の実演 - うんたらかんたらRuby - Rubyist)。
テストコードをリファクタリングしてみた。
余談だけど、gitで随時コミットするのがいいと思った。

describeのnest

全てGameに対するテストなのでnestしてみた。
対象を説明する時は describe, 状況を説明する時は context。

beforeを一纏め

#修正前抜粋
  context "すべてガターの場合" do 
    before do
      @game = Game.new
      20.times { roll_gutter }
    end

    it "スコアは0点" do
      @game.score.should == 0
    end
  end

beforeセクションは、Game.newが重複しまくっているので
これを一纏めに。
beforeセクションの内容は、テストの準備という位置づけの方が
いいような気がする(あとでもう少し調べる)ので
各beforeセクションで実行しているテスト条件の設定をitセクションへ移動してみた。

subjectを設定

#修正前
@game.score.should == 0

全テストで比較する対象が@game.scoreなので
subjectを設定

#修正後
  subject{ @game.score }


  should == 0

contextをさらにnest

(ここは余計かも)group化した方が見やすいかもと思ったので
10フレーム目の3つのテストを
contextで更にnestしてみた。

#修正後
  context "10フレーム目の場合" do
    context "1投目がストライクの場合" do
      it "スコアは17点" do
        18.times { roll_gutter }
        roll_strike
        @game.roll(3)
        @game.roll(4) # 17
        should == 17
      end
    end

    context "2投目がストライクの場合" do
      it "スコアは14点" do
        19.times { roll_gutter }
        roll_strike
        @game.roll(4) # 14
        should == 14
      end
    end

    context "スペアの場合" do
      it "スコアは14点" do
        18.times { roll_gutter }
        roll_spare
        @game.roll(4) # 14
        @game.score.should == 14
      end
    end
  end

修正前全部

require File.expand_path(File.dirname(__FILE__) + "/../game.rb")
#[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133

describe Game, "すべてガターの場合" do
  before do
    @game = Game.new
    20.times { roll_gutter }
  end

  it "スコアは0点" do
    @game.score.should == 0
  end
end

describe Game, "すべて1ピンの場合" do
  before do
    @game = Game.new
    20.times { @game.roll(1) }
  end

  it "スコアは20点" do
    @game.score.should == 20
  end
end

describe Game, "ストライクの場合" do
  before do
    @game = Game.new
    roll_strike
    @game.roll(3)
    @game.roll(4)
    18.times { roll_gutter }
  end

  it "スコアは24点" do
    @game.score.should == 24
  end
end

describe Game, "パーフェクトゲーム場合" do
  before do
    @game = Game.new
    12.times { roll_strike }
  end

  it "スコアは300点" do
    @game.score.should == 300
  end
end

describe Game, "スペアの場合" do
  before do
    @game = Game.new
    roll_spare
    @game.roll(4)
    @game.roll(3) # 21
    16.times { roll_gutter }
  end

  it "スコアは21点" do
    @game.score.should == 21
  end
end

#[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133
describe Game, "Uncle Bobの受け入れゲームの場合" do
  before do
    @game = Game.new
    [1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6].each {|pin| @game.roll pin}
  end

  it "スコアは133点" do
    @game.score.should == 133
  end
end

describe Game, "10フレーム目の1投目がストライクの場合" do
  before do
    @game = Game.new
    18.times { roll_gutter }
    roll_strike
    @game.roll(3)
    @game.roll(4) # 17
  end

  it "スコアは17点" do
    @game.score.should == 17
  end
end

describe Game, "10フレーム目の2投目がストライクの場合" do
  before do
    @game = Game.new
    19.times { roll_gutter }
    roll_strike
    @game.roll(4) # 14
  end

  it "スコアは14点" do
    @game.score.should == 14
  end
end

describe Game, "10フレーム目でスペアの場合" do
  before do
    @game = Game.new
    18.times { roll_gutter }
    roll_spare
    @game.roll(4) # 14
  end

  it "スコアは14点" do
    @game.score.should == 14
  end
end

private
def roll_gutter
  @game.roll(0)
end

def roll_strike
  @game.roll(10)
end

def roll_spare
  @game.roll(5)
  @game.roll(5)
end

修正後全部

多少見やすくなったかな。

require File.expand_path(File.dirname(__FILE__) + "/../game.rb")
#require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
#[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133

describe Game do
  before do
    @game = Game.new
  end

  subject{ @game.score }

  context "すべてガターの場合" do
    it "スコアは0点" do
      20.times { roll_gutter }
      should == 0
    end
  end

  context "すべて1ピンの場合" do
    it "スコアは20点" do
      20.times { @game.roll(1) }
      should == 20
    end
  end

  context "ストライクの場合" do
    it "スコアは24点" do
      roll_strike
      @game.roll(3)
      @game.roll(4)
      18.times { roll_gutter }
      should == 24
    end
  end

  context "パーフェクトゲーム場合" do
    it "スコアは300点" do
      12.times { roll_strike }
      should == 300
    end
  end

  context Game, "スペアの場合" do
    it "スコアは21点" do
      roll_spare
      @game.roll(4)
      @game.roll(3) # 21
      16.times { roll_gutter }
      should == 21
    end
  end

  #[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133
  context "Uncle Bobの受け入れゲームの場合" do
    it "スコアは133点" do
      [1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6].each {|pin| @game.roll pin}
      should == 133
    end
  end

  context "10フレーム目の場合" do
    context "1投目がストライクの場合" do
      it "スコアは17点" do
        18.times { roll_gutter }
        roll_strike
        @game.roll(3)
        @game.roll(4) # 17
        should == 17
      end
    end

    context "2投目がストライクの場合" do
      it "スコアは14点" do
        19.times { roll_gutter }
        roll_strike
        @game.roll(4) # 14
        should == 14
      end
    end

    context "スペアの場合" do
      it "スコアは14点" do
        18.times { roll_gutter }
        roll_spare
        @game.roll(4) # 14
        @game.score.should == 14
      end
    end
  end
end

private
def roll_gutter
  @game.roll(0)
end

def roll_strike
  @game.roll(10)
end

def roll_spare
  @game.roll(5)
  @game.roll(5)
end

テスト結果

spec -c -fs spec/game_spec.rb

Game すべてガターの場合
- スコアは0点

Game すべて1ピンの場合
- スコアは20点

Game ストライクの場合
- スコアは24点

Game パーフェクトゲーム場合
- スコアは300点

Game Game スペアの場合
- スコアは21点

Game Uncle Bobの受け入れゲームの場合
- スコアは133点

Game 10フレーム目の場合 1投目がストライクの場合
- スコアは17点

Game 10フレーム目の場合 2投目がストライクの場合
- スコアは14点

Game 10フレーム目の場合 スペアの場合
- スコアは14点

Finished in 0.007972 seconds

9 examples, 0 failures