モデルのバリデーションのテストをダラダラ書きたくない

RSpecでモデルのバリデーションのテストをダラダラ書かないで済むうまいやり方ってあるんでしょうか?
ダラダラ書かないで済む方法を模索してみました。


spec_helper.rbにこういうのを追加します。ここではバリデーションの種類はverify_hours(入力値が24(時間)以内かチェックする)だけあります。
種類を追加するときは、verify_hoursをまるっとコピーしたメソッドをつくって、valid_values、invalid_valuesの配列にそれぞれ有効値、無効値を書くだけです。

def verify_valid(klass, col_name, value)
  valid_check = Proc.new {
    attributes = @valid_attributes.merge(col_name.to_sym => value)
    obj = klass.new(attributes)
    obj.should be_valid
    obj.should have(0).errors_on(col_name.to_sym)
    obj.should have(0).errors
    obj.save.should be_true
  }
end

def verify_invalid(klass, col_name, value)
  invalid_check = Proc.new {
    attributes = @valid_attributes.merge("#{col_name}" => value)
    obj = klass.new(attributes)
    obj.should be_invalid
    obj.should have(1).errors_on(col_name.to_sym)
    obj.should have(1).errors
    obj.save.should be_false
  }
end

def verify_hours(klass, col_name)
  valid_values = [0, 3.5, 12, 24]
  invalid_values = [nil, "", "hankaku_moji", "全角文字", -1, -2.3, 25]

  valid_values.each{|value| it "#{col_name} 正常(#{value.inspect})", &verify_valid(klass, col_name, value) }
  invalid_values.each{|value| it "#{col_name} 異常(#{value.inspect})", &verify_invalid(klass, col_name, value)}
end


モデルのSpecにはこんな感じで書きます。

before(:each) do
  @valid_attributes = {
    #各項目がvalidになる値を定義しておく
  }
end

describe "target_attributeは1日の時間であること" do
  verify_hours(TargetClass, :target_attribute)
end


出力はこんな感じになります。

TargetClass target_attributeは1日の使用時間であること
- target_attribute 正常(0)
- target_attribute 正常(3.5)
- target_attribute 正常(12)
- target_attribute 正常(24)
- target_attribute 異常(nil)
- target_attribute 異常("")
- target_attribute 異常("hankaku_moji")
- target_attribute 異常("全角文字")
- target_attribute 異常(-1)
- target_attribute 異常(-2.3)
- target_attribute 異常(25)


ちょっと調べてみたところ、accept_values_forというマッチャを追加するよいソリューションがありました。
accept_values_for

describe User do
  subject { User.new(@valid_attributes)}
  it { should accept_values_for(:email, "john@example.com", "lambda@gusiev.com") }
  it { should_not accept_values_for(:email, "invalid", nil, "a@b", "john@.com") }
end

これはいいですね。