読者です 読者をやめる 読者になる 読者になる

RSpecで値を比較するときには'eq'を利用して'=='は利用しない方が良い

とあるプログラムを書いているときに思った通りの動作をしないケースがあり、RSpecで以下のような記述をしました。

[ruby] it 'sample' do expect(1) == 0 # => success end [/ruby]

一瞬目を疑いました。failとなるテストがsuccessとなっているのです。やはり、テストは大事なのですが、エラーとなるテストを書いてからテストが通るようにすることはとても重要なのです。

どうやら完全にRSpecのMatcherについて使い方を間違えていることがわかったので RSpec の仕様を確認しました。現在のバージョンでは正しくない記述方法のようです。同値性を確認する方法については以下の通り記述するべきでした。

[ruby] context '同値性の評価' do it 'should 記法を使用すると正しく fail となる' do 1.should == 0 # => fail end

  it 'eq で評価すると正しく fail となる' do
    expect(1).to eq 0 # => fail
  end

  it 'equal で評価すると正しく fail となる' do
    expect(1).to equal(0) # => fail
  end

  it 'eql で評価すると正しく fail となる' do
    expect(1).to eql(0) # => success
  end

  it 'be == で評価すると正しく fail となる' do
    expect(1).to be == 0 # => success
  end

  it '== で評価すると間違って success となる' do
    expect(1) == 0 # => success
  end
end

[/ruby]

※上記はRspecの公式ガイドを参考にしました。具体的には以下の部分が該当します。

rspec-expectations ships with matchers that align with each of these methods:
  expect(a).to equal(b) # passes if a.equal?(b)
  expect(a).to eql(b)   # passes if a.eql?(b)
  expect(a).to be == b  # passes if a == b
It also ships with two matchers that have more of a DSL feel to them:
  expect(a).to be(b) # passes if a.equal?(b)
  expect(a).to eq(b) # passes if a == b

Equality matchers - Built in matchers - RSpec Expectations - RSpec - Relish

「よく仕様を確認するべき」の一言に尽きますが、各バージョンで微妙に異なる記述方式をよく理解しないまま記述すのはこわいことです。特にテストコードはプロダクションコードのよりどころなので正しく動作することの前提が崩れてしまいいろいろとやばいことになります。

ということで、今日はやばいことを直して一日が終わってしまいました…。