メタプログラミングなテストは書くな
Jay Fields' Thoughts: Testing Anti-Pattern: Metaprogrammed Tests
ループとdefine_methodでテストメソッドを定義したらだめだという話。
- 行番号が意味なくなる。
- 失敗したテストが見つけにくくなる。
- テストが複雑になりすぎる。そのため、メンテナンス性がなくなってしまう。
こんなのはだめ。
require 'test/unit' class GradeTests < Test::Unit::TestCase (0..100).each do |index| letter = case index when 0..59 then "F" when 60..69 then "D" when 70..79 then "C" when 80..89 then "B" when 90..100 then "A" end define_method "test_#{index}_is_#{letter}" do assert_equal letter, index.as_letter_grade end end end
結果をEnumerableで持たせて比較したほうがマシ。全部同じ結果になるのでuniqでひとつにしちゃう。うまいなぁ。
class GradeTests < Test::Unit::TestCase def test_numbers_that_are_As assert_equal ["A"], (90..100).collect { |int| int.as_letter_grade }.uniq end def test_numbers_that_are_Bs assert_equal ["B"], (80..89).collect { |int| int.as_letter_grade }.uniq end # ... test the other letters end
げげっ、rcodetoolsのテストがもろmetaprogrammed testじゃん!なおさなあかんなぁ…