Rails 2.3.5 対応。 やっぱりテスト期待値にid を書くのは危険

先日リリース Rails 2.3.5がリリースされたので開発中のアプリをバージョンアップしてみました。 リリースノート にあるように2.3.5は基本的にはセキュリティー、バグ対応がメインで大きく変わったところは無いようです。

http://www.rubyonrails.org/images/rails.png

バージョンアップですが、アプリ側の変更は特になく environment.rb の RAILS_GEM_VERSION を '2.3.5' にするだけです。
後はテスト(RSpec, Cucumber, 人手) を行って問題がないかチェックするだけです。


今回のアプリでは、なんとRSpecの20%がエラーになってしまいまいました ^^);

'Product 商品一覧 selector 小分類指定の商品一覧' FAILED
expected: [["モンタナ", 283269207], ["ラビニアジーンズ", 1743087809], ["シンディコントラスト", 2129410426]],
     got: [["モンタナ", 283269208], ["ラビニアジーンズ", 669345987], ["シンディコントラスト", 1055668603]] (using ==)

エラーを見ると上のようにレコードの id の値が変わっています。微妙に変わっているものや大幅に変わっているものも・・・
ところで、このidですがFixture(テストデータ)の自動id生成機能が発生させています。今までのバージョンアップでは変わる事はありませんでしたが、今回は変わったようです。

さて、自動id生成機能はどうやってid値を作っているのでしょうか、コードは active_record/fixtures.rb の中にあります。

  def self.identify(label)
    Zlib.crc32(label.to_s) % MAX_ID
  end

上のコードから解るように、Fixtureに書かれたレコードのラベルの文字列のCRCを計算しMAX_ID以下の整数にしています。2.3.4 と 2.3.5 を比較すると

% diff activerecord-2.3.4/lib/active_record/fixtures.rb activerecord-2.3.5/lib/active_record/fixtures.rb
437c437
<   MAX_ID = 2 ** 31 - 1
---
>   MAX_ID = 2 ** 30 - 1

と、31bit整数の最大値から30bit整数の最大値に変更になっています。この変更でidの値が変わったのでした。



今回エラーになってしまったRSpecですが、期待値にidの値が書かれていることは好ましい事ではありませんので、products(:p001).id のようにFixtureのid値を取得するようなコードに変更しました。