LoginSignup
12

More than 5 years have passed since last update.

Minitestで例外クラスとエラーメッセージを検証する方法

Last updated at Posted at 2017-01-08

Minitestで例外クラスとエラーメッセージを検証する方法

Minitestで例外クラスと例外メッセージを検証する場合は、assert_raisesでまず例外クラスを検証し、その戻り値(例外オブジェクト)を使ってエラーメッセージを検証します。

以下はそのサンプルコードです。

次のようなクラスがあったとします。

class Foo
  # 例外が発生するメソッド
  def self.boo!
    raise 'BOO!!'
  end
end

boo! メソッドを呼び出すとRuntimeErrorが発生し、なおかつそのエラーメッセージが"BOO!!"であることを検証する場合は次のようなコードを書きます。

require 'minitest/autorun'

class FooTest < Minitest::Test
  def test_boo!
    # RuntimeErrorが発生することを検証
    e = assert_raises RuntimeError do
      Foo.boo!
    end

    # エラーメッセージを検証
    assert_equal 'BOO!!', e.message
  end
end

よくある間違い

assert_raises の第2引数に文字列を渡してもエラーメッセージを検証したことにはなりません。
以下のコードは間違いです。

require 'minitest/autorun'

class FooTest < Minitest::Test
  def test_boo!
    # このコードだと、エラーメッセージを検証できていない
    assert_raises RuntimeError, 'BOO!!' do
      Foo.boo!
    end
  end
end

assert_raises の第2引数は、検証が失敗したときに表示されるメッセージになります。
assert_raises 自体は例外クラスが一致するかどうかの検証しかしてくれません。

たとえば、次のように実際のエラーメッセージと異なる文字列を渡してもテストはパスします。

require 'minitest/autorun'

class FooTest < Minitest::Test
  def test_boo!
    # 第2引数は検証失敗時の表示用メッセージなので、'BOO!!'でなくてもパスする
    assert_raises RuntimeError, 'HAHAHA!!' do
      Foo.boo!
    end
  end
end

これは「パスすべきでないテストがパスする問題(false positive)」につながるので要注意です。

同様に、次のコードも間違いです。

require 'minitest/autorun'

class FooTest < Minitest::Test
  def test_boo!
    # これもやはりエラーメッセージを検証できていない
    assert_raises 'BOO!!' do
      Foo.boo!
    end
  end
end

例外クラスが省略された場合は、StandardErrorか、そのサブクラスの例外が発生した場合にパスします。
上のコードの'BOO!!'は例外クラスではなく文字列なので、先ほどと同様、検証失敗時に表示されるメッセージになります。

さらに:コードを読んで仕様を理解する

Minitestの実装コードはシンプルなので、assert_raisesメソッドのコードを読むと仕様の理解がさらに進むと思います。

参考:RSpecの場合

RSpecであれば、raise_errorマッチャを使って例外クラスとエラーメッセージを同時に検証できます。

# 例外クラスとエラーメッセージを同時に検証する
expect { Foo.boo! }.to raise_error RuntimeError, 'BOO!!'

文字列だけを渡したときはエラーメッセージだけを検証したことになります。

# エラーメッセージだけを検証する
expect { Foo.boo! }.to raise_error 'BOO!!'

次のようにブロックを使うと、例外オブジェクトを使って検証することもできます。

expect { Foo.boo! }.to raise_error RuntimeError do |e|
  expect(e.message).to eq 'BOO!!'
end

ぱっと見、raise_error マッチャとMinitestのassert_raises メソッドと用途や構文が似ているので、同じように使えそうな気がしますが、実際は微妙に異なるので注意が必要です。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12