Ruby で Test::Unit を使ってみる

プログラムを書いた後、本当にその動作するの?みたいなことを確かめるために、Ruby には Test::Unit というクラスがあります。

今回は、研究室の課題が出たので、それをテストの勉強と一緒にやってしまおうという話です。実はそんなことするつもりなかったんですが、発表が1週間遅れたのでちょっと余計なことをしてみようと。


テストにはテストする対象となるファイルと、どういうテストをするかのテストファイルが必要になります。


今回テスト対象のファイルは、ユニコードのデータが大量に書いてあるファイル(UnicodeData.txt)を、文字見つける・単語数える・たぶん似てる名前を見つけるという3つの分析っぽいことをしてみたものです。

class UnicodeData
	def analyze(unicode_number)	#分析用メソッド
		unless unicode_number =~ /^[\dA-F]+/	#16進数かどうか
			puts "#{unicode_number} is not hex number."	#16進数の数値を渡さなきゃダメ
		else
			open("UnicodeData.txt").each{|line|
				word = line.chomp.split(/;/)	#セミコロンごとに区切る
				str = [word[0].hex].pack('U')
				if word[0] == unicode_number	#値が等しければ
					puts "#{unicode_number} is #{str}"
					return str
				elsif word[0].hex > unicode_number.hex	#値が越えたら
					puts "#{unicode_number} is not exist."	#その値の文字は存在しない
					return str
				end
			}
		end
	end

	def wordcount(want)	#文字 want が何度登場するか数えるメソッド
		count = 0
		open("UnicodeData.txt").each{|line|
			word = line.chomp.split(/;/)	#セミコロンごとに区切る
			word[1].split(/ /).each{|w|	#二つ目に文字の名前があるので、それを空白で区切る
				count += 1 if w == want	#文字 want と同じだったら+1していく
			}
		}
		print "#{want} : #{count}\n"	#表示
		return count
	end
	
	def resemble(word1, word2)
		list = Hash.new
		open("UnicodeData.txt").each{|line|
			word = line.chomp.split(/;/)	#セミコロンごとに区切る
			next if word[10] == nil	#中身がないときは無視
			str = word[10].split(/ /)	#単語ごとで分ける
			st0, st1 = str[0], str[1]	#1つめと2つめの単語を確保
			if list.key?([st0, st1])	#前に使われていれば
				listst0, st1 << str	#同じキーで格納
			else
				list.store([st0, st1], [str])	#新しくキーと値を格納
			end
		}
		p listword1, word2	#表示
		return listword1, word2	#テストのため値を返す必要があるみたい
	end
end

ファイルをダウンロードしなきゃいけないのでそのままでは動きませんがご了承を。ファイル名は unicodedata.rb にしてあります。

これに対応して、テストファイル( test.rb )は以下のような感じ。

require 'test/unit'
require 'unicodedata'	#テストしたいファイルとtest/unitをrequireしておく

class UnicodeDataTest < Test::Unit::TestCase
	def setup	#一番初めに呼び出されるメソッド
		@obj = UnicodeData.new
	end
	
	def teardown	#1つテストが終わったら呼び出されるメソッド
		puts "\ttest finished."
	end
	
	def test_analyze	#メソッド名はtest_元ファイルでのメソッド名 とかがいいか
		str = ["0000", "ABCD", "A456", "4576", "JUE4"]
		str.each{|word|
			assert_equal([word.hex].pack('U'), @obj.analyze(word))
		}
	end
	
	def test_wordcount
		str = ["FIVE", "KATAKANA"]
		str.each{|word|
			assert_not_equal(0, @obj.wordcount(word))
		}
	end
	
	def test_resemble
		str = ["HALFWIDTH","HANGUL"]
		assert_not_nil(@obj.resemble(str[0], str[1]))
		assert_nil(@obj.resemble(str[1], str[0]))
	end
end

assert_* というのは Test::Unit::TestCase にあるメソッドで、色々あるのでリファレンスでも見てください。わざと失敗するようなテストも作ってありますが・・・。


この程度のものではテストする意味もなさそうなんですが、やはりプログラムが大きくなればなるほどテストの重要性が増していくようなので、これからは小さなプログラムでもテストを作って慣れていこうかな。

実行結果は研究室で見せ・・・られたら見せます。