Rubyの研修その1 - 自動テストに挑戦してみた
Ruby勉強中の僕が、簡単な自動テストに挑戦してみた話です。
この記事で使っているRubyのバージョンは2.1.4です。
まず、研修の課題でこんなものを書きました。コンピュータとじゃんけんで遊ぶことができる、夢のようなプログラムです。
janken.rb
janken = ["g", "c", "p"] output = {"g" => "グー", "c" => "チョキ", "p" => "パー"} you = gets.chomp if !janken.include?(you) then puts "g, c, p のいずれかを入力してください。" exit(1) end com = janken.sample print "あなたは", output[you], "、私は", output[com] if you == "g" && com == "c" || you == "c" && com == "p" || you == "p" && com == "g" then print "、あなたの勝ちです。\n" elsif you == com then print "、引き分けです。\n" else print "、あなたの負けです。\n" end
実行すると、標準入力の待ち状態になって、ユーザはg, c, pのいずれかを入力します。コンピュータはランダムにグー、チョキ、パーを出し、勝ち負けを判定し、結果を出力します。
ためしにやってみるとこんな感じになります。
$ ruby janken.rb g あなたはグー、私はパー、あなたの負けです。
さて、ここまで書いたところで、次の課題が言い渡されました。
偉い人「じゃんけんクラスを作って、勝ち負け判定だけを自動テストしてみましょう。自動テストはminitestを使いましょう(外のテストフレームワークでもいいけど)」
クラスはまあいいとして、minitestのことは全く知らなかったため、とりあえず調べてみることにします。頼りになるぜGoogle先生!
ふむふむ。わかったようなわからないような。メソッドの戻り値が期待通りになっているかどうか確かめる、という認識で良いのかしら。このライブラリは2.2.0で削除されましたって書いてあるけど、僕が今使っているのは2.1.4だからセーフ?
今回のケースではどんな風に書けばいいのか、偉い人に聞いてヒントをもらったりしながら、こんなものを作りました。
まずはテストの対象となるじゃんけんクラス。
class_janken.rb
class Janken def dasu(you, com) @you = you @com = com end def judge if @you == "g" && @com == "c" || @you == "c" && @com == "p" || @you == "p" && @com == "g" then return "win" elsif @you == @com then return "draw" else return "lose" end end end
次に、このクラスファイルを呼び出して利用する、メインの部分。これを実行すると、最初に挙げたじゃんけんプログラムと同じようにじゃんけんができます。
main_janken.rb
require './class_janken' pon = ["g", "c", "p"] output1 = {"g" => "グー", "c" => "チョキ", "p" => "パー"} output2 = {"win" => "、あなたの勝ちです。\n", "draw" => "、引き分けです。\n", "lose" => "、あなたの負けです。\n"} you = gets.chomp if !pon.include?(you) then puts "g, c, p のいずれかを入力してください。" exit(1) end com = pon.sample janken = Janken.new janken.dasu(you, com) print "あなたは", output1[you], "、私は", output1[com], output2[janken.judge]
最後に、今回のキモであるテストファイル。じゃんけんクラスから作成したオブジェクトに、グーチョキパーを合計9通り与えて、戻り値が期待通りになるかどうか調べるものです。
test_janken.rb
require 'minitest/autorun' require './class_janken' MiniTest::Unit.autorun class Testjanken < MiniTest::Unit::TestCase def setup @janken = Janken.new end def test_gwin @janken.dasu("g", "c") assert_equal "win", @janken.judge end def test_gdraw @janken.dasu("g", "g") assert_equal "draw", @janken.judge end def test_glose @janken.dasu("g", "p") assert_equal "lose", @janken.judge end def test_cwin @janken.dasu("c", "p") assert_equal "win", @janken.judge end def test_cdraw @janken.dasu("c", "c") assert_equal "draw", @janken.judge end def test_close @janken.dasu("c", "g") assert_equal "lose", @janken.judge end def test_pwin @janken.dasu("p", "g") assert_equal "win", @janken.judge end def test_pdraw @janken.dasu("p", "p") assert_equal "draw", @janken.judge end def test_plose @janken.dasu("p", "c") assert_equal "lose", @janken.judge end end
さっそくテストを実行してみます。
$ ruby test_janken.rb (略) Finished in 0.001686s, 5336.9830 runs/s, 5336.9830 assertions/s. 9 runs, 9 assertions, 0 failures, 0 errors, 0 skips
9通り全てのパターンで、戻り値が期待通りだったようです。めでたしめでたし。
手動でテストを行うと、コンピュータが何を出すかは完全にランダムなので、運が悪いと延々とじゃんけんを続けることになってしまいます。それに対して、自動テストを使うことで、0.002秒足らずで全てのパターンのテストを終えることができました。
今回テストの対象となったプログラムは非常に小さいものだったので、手動テストにかかる時間と自動テストのためのテストファイルの作成にかかる時間を比べると同じぐらいになるかもしれませんが、巨大なプログラムのテストをする際は、作業時間を短縮できるだけでなく、つまらないミスもなくせるので、非常に役に立ちそうですね。