Ruby
AdventCalendar
開発環境

RubyのTDDのベストプラクティス

More than 5 years have passed since last update.

この記事は、RubyのAdvent Calendarの2日目の記事です。
オライリーの『Rubyベストプラクティス』のテスト駆動開発の章をまとめました。
開発環境とrubyとテストに関する記述が入り交じっています。

テストができるように設計する

1.大きなテストにすると、失敗した場合に、どこが原因で引っかかったかわかりにくい
2.小さなテストを追加する→レッドになるようにする→グリーンにする→リファクタリングする→始めに戻る
3.単純なテストから追加する
4.可読性向上のため、mustメソッドを使う

must.rb
class TC_Foo < Test::Unit::TestCase
  def setup
    @obj = Foo.new
  end

  must "be foo" do
    assert_equal("foo", @obj.foo)
  end
  must "be bar" do
    assert_equal("bar", @obj.bar)
  end
end

mustメソッドの実装は下記の通り。
https://github.com/sandal/rbp/blob/master/testing/test_unit_extensions.rb

テスティングの基礎

1.上記と重なるが、レポートが詳細な意味を持つようにするために、テストケースは小さくアトミックに保つ
2.例外をテストする

例外が起きることを期待する場合
class LockBoxTest < Test::Unit::TestCase
  def setup
    @lock_box = LockBox.new( password:"secret",
                 content:"My secret message") 
  end

  must "raise an error when an invalid password is used" do
    assert_raises(LockBox::InvalidPassword) do
      @lock_box.unlock("kitten")
    end
  end
  must "Not raise error when a valid password is used" do
    assert_nothing_raised do
      @lock_box.unlock("secret")
    end
  end
end

3.rakeタスクを使ってテストを自動実行する

rake.rb
require 'rake/testtask'

task :default => [:test] 

Rake::TestTask.new do |test|
  test.libs << "test"
  test.test_files = Dir["test/test_*.rb"]
  test.verbose = true
end```
##高度なテストテクニック
1.外部とのインタラクションと内部処理を切り分ける
2.外部のテストには、モックとスタブを使う。おすすめはflexmockライブラリ

```ruby:
require 'flexmock/test_unit'

class HapinessTest < Test::Unit::TestCase
  def setup
    @questioner = Questioner.new
  end

  must "respond 'Good I'm Glad' when inquire_about_hapiness gets 'yes'" do
    stubbed = flexmock(@questioner,:ask => true)
    assert_equal "Good I'm Glad",stubbed.inquire_about_hapiness
  end

  must "respond 'That's Too Bad' when inquire_about_hapiness gets 'no'" do
    stubbed = flexmock(@questioner,:ask => false)
    assert_equal "That's Too Bad",stubbed.inquire_about_hapiness
  end
end

3.xmlの比較は、一つにまとめてするのではなく、nokogiriライブラリを使って分解してやろう

整理しておく

1.ライブラリファイルにテストを組み込む

if文でラップするだけ
class Foo
  #...
end  

if __FILE__ == $PROGRAM_NAME
  require "test/unit"

  class TestFoo < Test::Unit::TestCase
    #test
  end  
end

2.テストヘルパーを一つのファイルにまとめて定義して、pathで直接requireする
3.組み込みのアサートで間に合わないなら、カスタムアサーションをassert_blockでつくる

assert_block
def assert_in_zone(expected,person)
  assert_block("Expected #{person.inspect} to be in Zone #{expected}") do
    person.current_zone.eql?(Zone.new(expected))
  end
  assert_block("Expected #{person.inspect} not to be in Zone #{expected}") do
    !person.current_zone.eql?(Zone.new(expected))
  end
end```##後口上ruby特有のベストプラクティスというよりは、テスト一般のお話でした。
以前にRailsの2系を少し触った程度で、普段Rubyを使わないのですが、各方面からRails3系を推されたため、最近オライリーの『Rubyベストプラクティス』を現在読んでいるところです。何か良いtipsや本があればご紹介お願いします。