Rails 2.3.5 対応。 やっぱりテスト期待値にid を書くのは危険
先日リリース Rails 2.3.5がリリースされたので開発中のアプリをバージョンアップしてみました。 リリースノート にあるように2.3.5は基本的にはセキュリティー、バグ対応がメインで大きく変わったところは無いようです。
バージョンアップですが、アプリ側の変更は特になく 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値を取得するようなコードに変更しました。