【Ruby】miniテストのエラー

FJORD BOOT CAMP(フィヨルドブートキャンプ)の課題で実装しているボーリングスコア計算プログラムのテストでエラーが出たので原因をアウトプットしていきます。


エラー

  • ボーリングスコア計算プログラムのテストを実行すると下記のエラーが出た
bowling_object.rb:68:in `pinfalls': undefined method `split' for nil:NilClass (NoMethodError)

「splitメソッドのクラスがnilのため見つかりません。」と解釈、しかしクラスは定義しているはず...なぜ?と思いつつ起点を調べる

  • テストの起点は下記のコード
from bowling_object_test.rb:3:in `<main>'
  • 上記のコードはrequire してbowling_object.rbを読み込む部分。このときにエラーが発生していることがわかる
require './bowling_object'
  • ちなみにbowling_object.rbのファイルの中身は、こんな感じ
# frozen_string_literal: true

class Game
  ...
end

class Frame
  ...
end

class Shot
  ...
end

puts Game.new(ARGV[0]).calculate_score


原因/改善

  • 上記のコードでは、最後のputs Game.new(ARGV[0]).calculate_scoreがrequireしただけで実行されてしまう。つまりARGVが何もない状態で実行されてしまうため、最終的にエラーが発生してしまう。テストを書く際にrequireしたいことを考えると、puts Game.new(ARGV[0]).calculate_scoreはこのファイル自体をrubyコマンドとして実行したときだけ走って欲しい。そんなときは以下のように書く
if __FILE__ == $PROGRAM_NAME
  puts Game.new(ARGV[0]).calculate_score
end
  • __FILE__:現在のファイルの名前を含むマジック変数。rubyは__FILE__を使用して現在のソースファイル名を保持する

  • $PROGRAM_NAME:変数名の先頭に$を付けると、グローバル変数を示す。変数名には実行中のスクリプトの名前が含まれる。PROGRAM_NAMEは、プログラムの名前を文字列で返す定数


そもそもテストコードはクラスのメソッドをテストするだけなので、ファイルを分けるとエラーは起きないということも学んだ。クラスを使ってコードを書く時は、クラスごとにファイルを分けることが重要!