Rubyで動的に関数定義3
で書いた方法をつかって、PerlのTest::Baseっぽいのを書いてみる。
(Ruby Test::Baseってのがすでにあるみたいだけどね。)
まずは、test_base.rb
require 'test/unit'
class TestBase < Test::Unit::TestCase
@@test_template = {}
def run(*args)
return if@method_name.to_s == "default_test"
super
end
def self.start_test
self.parse if(@@test_template.empty?)
self.generate_tests
end
private
def self.parse
test_name = ""
buf = ""
buf_mode = ""
while line = DATA.gets do
line.chomp!
if(line =~ /^(===|---)/)
if(buf != "" && test_name != "" && buf_mode != "")
@@test_template[test_name][buf_mode] = eval(buf)
buf = ""
end
if(line =~ /^=== (.*)$/)
test_name = $1
@@test_template[test_name] = {}
elsif(line =~ /--- input (.*)$/)
@@test_template[test_name][:method_name] = $1
buf_mode = :input
elsif(line = ~/--- expected/)
buf_mode= :expected
end
else
buf += line
end
end
if(buf != "" && test_name != "" && buf_mode != "")
@@test_template[test_name][buf_mode] = eval(buf)
buf = ""
end
end
def self.generate_tests
@@test_template.each do |test_name,test_args|
define_method(test_name) do
result=__send__(test_args[:method_name],test_args[:input])
assert_equal test_args[:expected], result, " error on #{test_name}"
end
end
end
end
DATAの処理のところが、ちょっと(かなり?)スパゲッティーだけど、generate_testsの所でテスト用の関数をDATA内容に合わせて作成してる。
Test::Unit::TestCaseのrunメソッドで”default_test”を無視するようにして、TestCaseがテスト未定義時に勝手にdefault_testを実行するのを防いでる。(この部分を抜くとどうなるか試せば言ってる意味がわかるはず)
実際のテストのほうは、こんな感じで書く。
require './test_base'
require './testee'
class TestBaseTest < TestBase
def setup #setupとかは通常のTestCaseと同じ
@testee = Testee.new
end
def login_test(login_name) # DATAを利用するテストはtest_以外のメソッド名
@testee.login(login_name)
@testee.who_am_i?
end
def test_without_data # DATAを使わないテストはtest_で始まるメソッド名
true
end
end
TestBaseTest.start_test #最後にstart_testでテストを生成しておく
__END__ #ここからテストに渡すパラメータ
=== test_should_login_by_hoge
--- input login_test #inputの後ろに利用するメソッド名
:hoge
--- expected
:hoge
=== test_should_login_by_fuga
--- input login_test
:fuga
--- expected
:fuga
inputの後ろのメソッド名が一個しかかけなかったり、フィルタとか便利なものがなかったり、”ruby Test::Base”よりかなりはしょってるけど、1ファイルで出来てるのでその辺はしょうがないと割り切る。
じゃあの。