Rubyノート - Test::Unit におけるテストの順番

しょうもない思い込みのせいで陥穽にハマって思い切り時間をロスw
ああ、無意識に前提していることって恐いな。

昨日から謎のエラーでテストがコケるもんで、原因は何だろうかと悪戦苦闘していたわけだが、原因はテストメソッド(def test_xxx)の実行順序をメソッドの定義順序だと勝手に思い込み、直前に記述したテストメソッドの実行結果(副作用)を前提したテストメソッドを書いてしまっていたことにあった。要するに、

def test_save
  # do something
end
def test_load
  # do something
end

前者が書き出すファイルを後者で読み取ってあれこれ検査、みたいなことを当たり前のようにやってたw しかも、ファイルは後処理で削除しないで残すようになってるので、実は前回のテストで書き出したファイルを読んだりしてた。恥ずかしいwww

これでセーブとロードの一貫性が取れなくなって、テストがコケていた。テスト後に残るファイルをいくら眺めても、それは test_load でロードされているものとは違うのだから、原因がわかるわけもなかったのだ。

大体、メソッドの名前とメソッド本体の対応は処理系がハッシュで管理しているはずだから、メソッドの定義順などが保存されているわけがないのである。

$ irb
irb(main):001:0> class Hoge
irb(main):002:1> def aaa
irb(main):003:2> end
irb(main):004:1> def bbb
irb(main):005:2> end
irb(main):006:1> def ccc
irb(main):007:2> end
irb(main):008:1> end
=> nil
irb(main):009:0> Hoge.instance_methods(false)
=> ["bbb", "aaa", "ccc"]

ほれ。Test::Unit でも定義されたテストメソッドの一覧を instance_methods で得ているはずだから、そりゃ実行順序なんか前提にできませんがな。

実際、テストメソッドの実行されていく順番を調べると、それは定義順ではなくて、アルファベット順だった。Test::Unit の方で instance_methods(false).sort とかやってんだろう。だから上の例では必ずセーブよりロードが先にくるわけだ。あちゃー。

自分の場合、開発の進行とともにテストメソッドを追加していくので、テストが追加した順に実行されることを無意識のうちに期待してしまっているところがある。B が通ったから次は C、それが通ったから今度は A という感じでテストを書いているうち、なんとなく、B → C → A という論理的なテストの順番が自分の中ででき上がってしまい、いつに間にやらそれを前提にテストを書い(ry

プログラミングの心理学(笑)