Rubyで書いたジャンケンのコードを`Unitテストする方法を調べたのでメモします。
Unitテストとは
Unitテストはざっくり、ばっさり言うと関数やメソッドといった最小の機能単位で、期待した動作が得られるかどうかを確認することらしい。システム全体として正しく動いているかをテストするのはテストフェーズになるが、Unitテストはテストフェーズまで待たずに、プログラマがソースを書いた時に、一緒にやってしまうのが主流とのこと。プログラマ大変^^;
Unitテストはプログラマの負荷が倍増する恐ろしいものだけど、最終的にはUnitテストをきっちりしておくと、手戻りなどが無くなってプログラマ本人が特をするそう。
参考文献
まとめ:
親父の小言と冷たい酒、Unitテストは、今は効かぬが後で効く。
RubyバンドルのテストUnitの歴史
歴史を調べるつもりはなかったが、どんなテスト用フレームワークがあるか調べていたら歴史に行き着きました。こんな感じのRuby用Testing frameworkの歴史みたいです。
Testing framework | 歴史(ざっくり) |
---|---|
RubyUnit Lapidary |
RubyUnit と Lapidaryというtesting frameworkがRuby用のたぶん最初のもの |
Test::Unit | 上記の2つが統合してTest::Unitになる。これがRuby1.8からバンドルされ、名前をtest/unit, test-unitなどに変えながらも標準testing frameworkの座を守る。 |
minitest | Test::Unitの複雑さに異を唱える人が表れる。なんとTest::Unitのメンテナー。もっと軽くて小さくて管理のし易いものにしたいと思い、miniunit(後のminitest)を生み出す。Ruby 1.9.1から現在に至るRuby標準バンドルTesting frameworkになる。 |
RSpec | RubyのバンドルTesting frameworkの歴史には全く登場しないものの、Railsの超有名チュートリアルサイトで取り上げられるなど、幅広い支持を得ている。 |
ということで、今回のテストでは標準バンドルされているminitestを使用することにします。
参考文献
minitestの使い方
とにかくminitestを動かす
ここを参考に、そもそもバンドルのminitestが動作するかを確認
http://allabout.co.jp/gm/gc/452071/
上記サイトでは最初にGemを使ってminitestを入れているが、この手順は省略。バンドルのminitestで動作するか確認。
test_janken.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
require 'minitest/autorun' class MyClass def add(x, y) x + y end end class TestMyClass < Minitest::Test def setup @myClass = MyClass.new end def test_add assert_equal 5, @myClass.add(2, 3) end end |
1 2 3 4 |
MyMBA:ruby_janken meguroman$ ruby test_janken.rb /Users/meguroman/.rbenv/versions/2.1.4/lib/ruby/2.1.0/minitest/unit.rb:26:in `const_missing': uninitialized constant MiniTest::Test (NameError) from test_janken.rb:9:in `<main>' |
1 2 |
class TestMyClass < Minitest::Test |
を
1 2 |
class TestMyClass < Minitest::Unit::TestCase |
にすると動いた。以下が参考になった。
https://github.com/seattlerb/minitest/issues/280
実行結果はこちら。1つのテストで予想値を得られたことが確認できた。
1 2 3 4 5 6 7 8 9 10 11 12 |
MyMBA:ruby_janken meguroman$ ruby test_janken.rb Run options: --seed 32754 # Running tests: . Finished tests in 0.000677s, 1477.1049 tests/s, 1477.1049 assertions/s. 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips MyMBA:ruby_janken meguroman$ |
外部の–.rbファイルをテストコードに読み込んでunittestする
本番の開発を想定すると、システム開発の本番ファイルとテストコードは、別々の.rbファイルになる。なので、テストコードに外部の本番コードを読み込んでテストする。
本番コード(外部ファイル)をjanken.rbとし、テストコードと同じディレクトリにあるとすると、
1 2 |
require './janken.rb' |
の書式で外部ファイルを読み込める。参考サイトによっては、
1 2 |
require 'janken' |
と書いてあるが、これだとRuby 2.1.4ではエラーが出たので、以下のサイトを参考に修正した。
http://blog.ruedap.com/2011/05/31/ruby-require-load-path
完成形は以下のとおり。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
require 'minitest/autorun' require './janken.rb' class TestMyClass < Minitest::Unit::TestCase def setup @myClass = MyClass.new end def test_add assert_equal 5, @myClass.add(2, 3) end end |
本番プログラム(ジャンケンするプログラム)のテストで使ってみる
本番プログラムのソース
まず、ジャンケンプログラムのコード
main.rb
1 2 3 4 5 6 |
require './janken.rb' # ジャンケンプログラム実行 janken = Janken.new janken.judge |
janken.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
class Janken_print # ジャンケンの内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # コンストラクタ - 引数をインスタンス変数へ格納 # @param [String] player_hand プレイヤーの手を表す文字列(g, c, p) # @param [String] com_hand コンピュータの手を表す文字列(g, c, p) # @param [String] result 勝敗結果を表す文字列(win, lose, draw) def initialize(player_hand, com_hand, result) @player_hand = player_hand @com_hand = com_hand @result = result end # ジャンケンの手を表す内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # @param [String] hand 手を表す文字列(g, c, p) # @return [String] 手を表す文字(画面出力用:「グー」「チョキ」「パー」) def hand_to_string(hand) case hand when 'g' return 'グー' when 'c' return 'チョキ' when 'p' return 'パー' end end # 勝敗結果を表す内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # @param [String] result 勝敗結果を表す文字列(win, lose, draw) # @return [String] 勝敗結果を表す文字列(画面出力用) def result_to_string(result) case result when 'win' return 'あなたの勝ち' when 'lose' return 'あなたの負け' when 'draw' return '引き分け' end end #結果の画面出力 def disp_result # 結果出力 p 'あなたは' + hand_to_string(@player_hand) p '、私は' + hand_to_string(@com_hand) p '、' + result_to_string(@result) + 'です。' end end class Janken # ジャンケンを実行する # プレイヤーの手を標準入力から取得 def get_player_hand # プレイヤーのジャンケンの手を取得 @player_hand = STDIN.gets.chomp! end # コンピュータの手をランダムに生成 def get_com_hand # コンピューター側のジャンケン手を生成 rand_num = rand(3) + 1 case rand_num when 1 @com_hand = 'g' when 2 @com_hand = 'c' when 3 @com_hand = 'p' end end # プレイヤー、コンピュータの手、及び、勝敗を画面出力 def result janken_print = Janken_print.new(@player_hand, @com_hand, @result) janken_print.disp_result end # プレイヤーとコンピュータの勝敗を決定 def judge #プレイヤー、コンピュータの手を取得 get_player_hand get_com_hand # 勝敗判定 case @player_hand when 'g' @result = 'win' if @com_hand == 'c' @result = 'lose' if @com_hand == 'p' @result = 'draw' if @com_hand == 'g' when 'c' @result = 'win' if @com_hand == 'p' @result = 'lose' if @com_hand == 'g' @result = 'draw' if @com_hand == 'c' when 'p' @result = 'win' if @com_hand == 'g' @result = 'lose' if @com_hand == 'c' @result = 'draw' if @com_hand == 'p' end # 結果の画面出力 result end end |
このプログラムにテストをしていく。
標準入力取得部分のUnitテスト
以下の様な標準入力を取得して、インスタンス変数に格納する部分をテストする。
1 2 3 4 5 6 |
# プレイヤーの手を標準入力から取得 def get_player_hand # プレイヤーのジャンケンの手を取得 @player_hand = STDIN.gets.chomp! end |
これがいきなり難しい、前述のサンプルのassert-equalとかではテストできなさそう。まず、標準入力をテストプログラムから与える部分をどうやって書けばいいかが分からない。どうやら「スタブ」や「モック」というテクを使うらしい。
参考
http://d.hatena.ne.jp/saliy1/20100724/1279980413
まずはget_player_handに直接STDINだと、テストの入力値を渡せないので、以下のように、オブジェクト生成時に入力値を渡せるように変更した。もちろん、入力値を渡してくるのはテストプログラム。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Janken def initialize(user_input=STDIN) @input = user_input end # プレイヤーの手を標準入力から取得 def get_player_hand # プレイヤーのジャンケンの手を取得 @player_hand = @input.gets.chomp end ... end |
あとは、テストプログラムの中でJanken.newするときに、StringIOというオブジェクトを渡す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
require 'minitest/autorun' require "stringio" require './janken.rb' class TestJanken < Minitest::Unit::TestCase def setup @in = StringIO.new() @janken = Janken.new(@in) end def test_get_player_hand @in << "g" @in.rewind assert_equal "g", @janken.get_player_hand end end |
このStringIOは文字列をIOオブジェクト(標準入力STDINや出力STDOUTなどで使うオブジェクト)のように扱うことができるオブジェクト。
コレを使うと @in << “g” というように、あとから入力値を渡せる。つまり、ジャンケンプログラムを実行した後に、標準入力から”g”という文字を打ちこむのと同様の状況をシミュレートしてくれる。
IOオブジェクト.rewindというのは、ファイルポインタを先頭に移動するメソッド。
1 2 3 4 5 6 |
f = File.new("testfile") f.readline #=> "This is line one\n" f.rewind #=> 0 f.lineno #=> 0 f.readline #=> "This is line one\n" |
これでassert_equal “g”, @janken.get_player_handを実行すると、標準入力のテスト項目をクリアできた。
case分で複数種類の返り値が得られる場合のUnitテスト
標準入力以外の部分のテストプログラムの方法は、ググった情報で十分対応して行けそう。ジャンケンプログラムのソースはcase文で値を返すメソッドが多いので、返り値が想定範囲内であることをテストするassert_includesを使えば良さそう。これでコンピュータのジャンケンの手をランダム生成するメソッドのテストを以下のように書いてみた。
1 2 3 4 5 6 |
def test_get_com_hand 10.times do assert_includes(%w[g c p], @janken.get_com_hand) end end |
返り値はランダムだが、数学的には33.3…%なので、偏りも考慮して10回テストすることにした。
次にプレイヤーとコンピュータの手から勝敗を決定するロジック部分のテストをする。が、以下のようにjudge メソッドの中にプレイヤーとコンピュータの手を取得していたために、テストがしづらくなっていることに気づいた。
テストプログラムからプレイヤーとコンピュータの手を入力値として与え、正しい勝敗結果が出力されるかをテストしたいが、入力値がjudgeメソッドの中で固定になっている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# プレイヤーとコンピュータの勝敗を決定 def judge #プレイヤー、コンピュータの手を取得 get_player_hand get_com_hand # 勝敗判定 case @player_hand when 'g' @result = 'win' if @com_hand == 'c' @result = 'lose' if @com_hand == 'p' @result = 'draw' if @com_hand == 'g' when 'c' @result = 'win' if @com_hand == 'p' @result = 'lose' if @com_hand == 'g' @result = 'draw' if @com_hand == 'c' when 'p' @result = 'win' if @com_hand == 'g' @result = 'lose' if @com_hand == 'c' @result = 'draw' if @com_hand == 'p' end # 結果の画面出力 result end |
テストを考えて、judgeメソッドを以下のように修正した。judgeメソッドの引数として、プレイヤーとコンピュータの手を与えられるようにした。引数を何も与えなければ、今までどおりインスタンス変数のプレイヤーとコンピュータの手を取得する。
一つ注意点はreturn @resultを末尾に加えたこと。Rubyは最終行が返り値になるとのことだったので、returnを書かなくてもcase文内の条件適合行(つまり@result)が返り値になると思っていたが、returnで明示的に@resultしないとテストプログラムで得られるjudgeメソッドの返り値はnilになった。前述のコンピュータの手のランダム生成メソッドget_com_handでは同じcase文の記述で返り値が得られたのに…何でだろう??
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# プレイヤーとコンピュータの勝敗を決定 def judge(player_hand=@player_hand, com_hand=@com_hand) case player_hand when 'g' @result = 'win' if com_hand == 'c' @result = 'lose' if com_hand == 'p' @result = 'draw' if com_hand == 'g' when 'c' @result = 'win' if com_hand == 'p' @result = 'lose' if com_hand == 'g' @result = 'draw' if com_hand == 'c' when 'p' @result = 'win' if com_hand == 'g' @result = 'lose' if com_hand == 'c' @result = 'draw' if com_hand == 'p' end return @result end |
judgeメソッドから省いた、クラス内の各メソッドを呼び出すmain的な処理は、resultメソッドに全てまとめた。resultメソッドはメソッドの呼び出しのみを行うメソッド。つまり、システム全体の処理を行っているので、Unitテストの対象にはならない。と思う。たぶん。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# プレイヤー、コンピュータの手、及び、勝敗を画面出力 def result #プレイヤー、コンピュータの手を取得 get_player_hand get_com_hand #勝敗の判定 judge # 結果の画面出力 janken_print = Janken_print.new(@player_hand, @com_hand, @result) janken_print.disp_result end |
最終的なjudgeのテストプログラムは以下のように書いた。全9通りをテスト。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 勝敗を判定するjudgeメソッドのテスト def test_judge assert_equal("win", @janken.judge("g", "c")) assert_equal("win", @janken.judge("c", "p")) assert_equal("win", @janken.judge("p", "g")) assert_equal("lose", @janken.judge("g", "p")) assert_equal("lose", @janken.judge("c", "g")) assert_equal("lose", @janken.judge("p", "c")) assert_equal("draw", @janken.judge("g", "g")) assert_equal("draw", @janken.judge("c", "c")) assert_equal("draw", @janken.judge("p", "p")) end |
画面出力クラスのUnitテスト
Unitテストを意識するとクラスやメソッドの作りの悪さが分かってくる。画面出力クラスJanken_printは当初以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
class Janken_print # ジャンケンの内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # コンストラクタ - 引数をインスタンス変数へ格納 # @param [String] player_hand プレイヤーの手を表す文字列(g, c, p) # @param [String] com_hand コンピュータの手を表す文字列(g, c, p) # @param [String] result 勝敗結果を表す文字列(win, lose, draw) def initialize(player_hand, com_hand, result) @player_hand = player_hand @com_hand = com_hand @result = result end # ジャンケンの手を表す内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # @param [String] hand 手を表す文字列(g, c, p) # @return [String] 手を表す文字(画面出力用:「グー」「チョキ」「パー」) def hand_to_string(hand) case hand when 'g' return 'グー' when 'c' return 'チョキ' when 'p' return 'パー' end end # 勝敗結果を表す内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # @param [String] result 勝敗結果を表す文字列(win, lose, draw) # @return [String] 勝敗結果を表す文字列(画面出力用) def result_to_string(result) case result when 'win' return 'あなたの勝ち' when 'lose' return 'あなたの負け' when 'draw' return '引き分け' end end #結果の画面出力 def disp_result # 結果出力 p 'あなたは' + hand_to_string(@player_hand) p '、私は' + hand_to_string(@com_hand) p '、' + result_to_string(@result) + 'です。' end end |
これをUnitテストするときに気づいたが、initializeでわざわざプレイヤー、コンピュータの手、勝敗結果をインスタンス変数化しているが、このインスタンス変数を使用するのはJanken_printクラスにある3つのメソッドのうちdisp_resultの1つのみ。なので、インスタンス変数化した意味が無い。
また、この仕様のせいで、Janken_printクラスをテストする場合、入力値(ジャンケンの手)を変更するためにはJanken_printクラスを何回もオブジェクト化しなければいけない。
ということで、以下のように、プレイヤー、コンピュータの手、勝敗結果はdisp_resultメソッドの引数として、渡すように変更した。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
class Janken_print # ジャンケンの内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # ジャンケンの手を表す内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # @param [String] hand 手を表す文字列(g, c, p) # @return [String] 手を表す文字(画面出力用:「グー」「チョキ」「パー」) def hand_to_string(hand) case hand when 'g' return 'グー' when 'c' return 'チョキ' when 'p' return 'パー' end end # 勝敗結果を表す内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # @param [String] result 勝敗結果を表す文字列(win, lose, draw) # @return [String] 勝敗結果を表す文字列(画面出力用) def result_to_string(result) case result when 'win' return 'あなたの勝ち' when 'lose' return 'あなたの負け' when 'draw' return '引き分け' end end #結果の画面出力 def disp_result(player_hand, com_hand, result) # 結果出力 p 'あなたは' + hand_to_string(player_hand) p '、私は' + hand_to_string(com_hand) p '、' + result_to_string(result) + 'です。' end end |
これにともない、Jankenクラスのresultメソッドも以下のように変更
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Janken ... # プレイヤー、コンピュータの手、及び、勝敗を画面出力 def result #プレイヤー、コンピュータの手を取得 get_player_hand get_com_hand #勝敗の判定 judge # 結果の画面出力 janken_print = Janken_print.new(@player_hand, @com_hand, @result) janken_print.disp_result end ... end |
上記の対応で、ぐっとUnitテストがやりやすくなった。ジャンケンの手と勝敗結果の画面出力文字列への変換メソッドhand_to_stringとresult_to_stringは以下のようにサクッと書けた。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class TestJanken_print < Minitest::Unit::TestCase def setup @janken_print = Janken_print.new end # ジャンケンの手を内部変数から画面表示文字列に変換するhand_to_stringメソッドのテスト def test_hand_to_string assert_equal("グー", @janken_print.hand_to_string("g")) assert_equal("チョキ", @janken_print.hand_to_string("c")) assert_equal("パー", @janken_print.hand_to_string("p")) end # 勝敗を表す内部変数から画面表示文字列に変換するresult_to_stringメソッドのテスト def test_result_to_string assert_equal("あなたの勝ち", @janken_print.result_to_string("win")) assert_equal("あなたの負け", @janken_print.result_to_string("lose")) assert_equal("引き分け", @janken_print.result_to_string("draw")) end end |
ただ、最後の最終結果の画面出力disp_resultメソッドのUnitテストで問題が。以下のようにメソッド内でprintするとreturn値が得られないのでUnitテストができなかった。
1 2 3 4 5 6 7 8 |
#結果の画面出力 def disp_result(player_hand, com_hand, result) # 結果出力 print 'あなたは' + hand_to_string(player_hand) print '、私は' + hand_to_string(com_hand) print '、' + result_to_string(result) + "です。\n" end |
なので、以下のようにdisp_resultメソッドでは最終結果の文字列をreturnして、このメソッドを呼び出す側でputsして画面出力するほうが良い。これからはテストを意識しながら本番コードも作り始めたほうが良さそうだ。(そう開発手法をTDDというらしい)
1 2 3 4 5 6 7 8 9 10 |
#結果の画面出力 def disp_result(player_hand, com_hand, result) # 結果出力 game_result = 'あなたは' + hand_to_string(player_hand) game_result << '、私は' + hand_to_string(com_hand) game_result << '、' + result_to_string(result) + "です。\n" return game_result end |
1 2 |
puts janken_print.disp_result(@player_hand, @com_hand, @result) |
という感じで、最終的なテストコード、ジャンケンプログラムは以下のようになった。テストを通してジャンケンプログラム自体も洗練されてきた気がする。
main.rb
1 2 3 4 5 6 |
require './janken.rb' # ジャンケンプログラム実行 janken = Janken.new janken.result |
janken.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
class Janken_print # ジャンケンの内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # ジャンケンの手を表す内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # @param [String] hand 手を表す文字列(g, c, p) # @return [String] 手を表す文字(画面出力用:「グー」「チョキ」「パー」) def hand_to_string(hand) case hand when 'g' return 'グー' when 'c' return 'チョキ' when 'p' return 'パー' end end # 勝敗結果を表す内部変数(String)を日本語の画面出力表示文字列(String)に置き換える # @param [String] result 勝敗結果を表す文字列(win, lose, draw) # @return [String] 勝敗結果を表す文字列(画面出力用) def result_to_string(result) case result when 'win' return 'あなたの勝ち' when 'lose' return 'あなたの負け' when 'draw' return '引き分け' end end #結果の画面出力 def disp_result(player_hand, com_hand, result) # 結果出力 game_result = 'あなたは' + hand_to_string(player_hand) game_result << '、私は' + hand_to_string(com_hand) game_result << '、' + result_to_string(result) + "です。\n" return game_result end end class Janken # ジャンケンを実行する def initialize(user_input=STDIN) @input = user_input end # プレイヤーの手を標準入力から取得 def get_player_hand # プレイヤーのジャンケンの手を取得 @player_hand = @input.gets.chomp end # コンピュータの手をランダムに生成 def get_com_hand # コンピューター側のジャンケン手を生成 rand_num = rand(3) + 1 case rand_num when 1 @com_hand = 'g' when 2 @com_hand = 'c' when 3 @com_hand = 'p' end end # プレイヤーとコンピュータの勝敗を決定 def judge(player_hand=@player_hand, com_hand=@com_hand) case player_hand when 'g' @result = 'win' if com_hand == 'c' @result = 'lose' if com_hand == 'p' @result = 'draw' if com_hand == 'g' when 'c' @result = 'win' if com_hand == 'p' @result = 'lose' if com_hand == 'g' @result = 'draw' if com_hand == 'c' when 'p' @result = 'win' if com_hand == 'g' @result = 'lose' if com_hand == 'c' @result = 'draw' if com_hand == 'p' end return @result end # プレイヤー、コンピュータの手、及び、勝敗を画面出力 def result #プレイヤー、コンピュータの手を取得 get_player_hand get_com_hand #勝敗の判定 judge # 結果の画面出力 janken_print = Janken_print.new puts janken_print.disp_result(@player_hand, @com_hand, @result) end end |
test_janken.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
require 'minitest/autorun' require "stringio" require './janken.rb' class TestJanken < Minitest::Unit::TestCase def setup @in = StringIO.new() @janken = Janken.new(@in) end # 標準入力取得のget_player_handメソッドのテスト def test_get_player_hand # 標準入力をStringIOでシミュレートして渡す。 @in << "g" @in.rewind assert_equal "g", @janken.get_player_hand end # コンピュータの手をランダム生成するget_com_handメソッドのテスト def test_get_com_hand 10.times do assert_includes(%w[g c p], @janken.get_com_hand) end end # 勝敗を判定するjudgeメソッドのテスト def test_judge assert_equal("win", @janken.judge("g", "c")) assert_equal("win", @janken.judge("c", "p")) assert_equal("win", @janken.judge("p", "g")) assert_equal("lose", @janken.judge("g", "p")) assert_equal("lose", @janken.judge("c", "g")) assert_equal("lose", @janken.judge("p", "c")) assert_equal("draw", @janken.judge("g", "g")) assert_equal("draw", @janken.judge("c", "c")) assert_equal("draw", @janken.judge("p", "p")) end end class TestJanken_print < Minitest::Unit::TestCase def setup @janken_print = Janken_print.new end # ジャンケンの手を内部変数から画面表示文字列に変換するhand_to_stringメソッドのテスト def test_hand_to_string assert_equal("グー", @janken_print.hand_to_string("g")) assert_equal("チョキ", @janken_print.hand_to_string("c")) assert_equal("パー", @janken_print.hand_to_string("p")) end # 勝敗を表す内部変数から画面表示文字列に変換するresult_to_stringメソッドのテスト def test_result_to_string assert_equal("あなたの勝ち", @janken_print.result_to_string("win")) assert_equal("あなたの負け", @janken_print.result_to_string("lose")) assert_equal("引き分け", @janken_print.result_to_string("draw")) end # 最終的なじゃんけんゲームの画面出力を行うdisp_resultメソッドのテスト def test_disp_result assert_equal("あなたはグー、私はパー、あなたの負けです。\n", @janken_print.disp_result("g", "p", "lose")) end end |
その他に覚えたhacks
- %w[foo bar baz]と書くと[“foo”, “bar”, “baz”]の配列が得られる。配列リテラルと言うテクらしい。