2016-10-14 3 views
4

のために繰り返したい、私は正確に同じ2つのテストになってしまいました最初にxを入力し、その後にyの仕様を追加します。乾いた状態に保つが、私のRoRのモデルのための私の進化rspecsにおけるだから、さまざまな理由

明らかに、リファクタリングする時間。彼らは重複しているので、私は仕様の1つを削除することができます:それは乾燥したままにしてください。

ここで、各スペックの内部構造はまったく同じですが、itの説明が異なります。私はそこに含まれている情報を失いたくはありません。

私の質問です - この場合、重複した仕様をそのまま保つことはできますか?それらをマージして、itの説明に改名する必要がありますか?おそらく:

it 'is valid when x is zero and y is ten' do 
    foo = build(:foo, x: 0, y: 10) 
    expect(foo.valid?).to be_truthy 
end 

しかし、私の心に、私は今、二つのこと(フー・モデルにおける2検証条項)をテストしている1つのスペックを持っています。それも良いことではありません。潜む匂いがします。

私が見逃した別のアプローチはありますか?

+0

それが依存 –

+0

私見両方のテストを持っているとは全く許容できます。最初のテストで 'y:nil'を渡すべきでしょうか? 'y:false'で? 「y:MyY.new」と一緒に?そうでなければ、あなたはすでに問題に陥っています。一つは、テストされているものが欲しい。私は '{x、y}∈[良い、悪い] 'の4つのテストに行きます。 – mudasobwa

+1

['#be_valid'](http://www.rubydoc.info/gems/rspec-rails/RSpec%2FRails%2FMatchers%3Abe_valid)を使用すると、' valid? 'が真実であることをなぜテストするのですか? 'expect(foo).to be_valid'アイデアはまったく同じで、私の意見ではそれをより読みやすくしています。 – engineersmnky

答えて

2

私はDRYについて心配するつもりはありません。あなたが意図する動作を実際にカバーする仕様を書くことについては、私は心配しています。

it 'is valid when x is zero' do 
    foo = build(:foo, x: 0) 
    expect(foo.valid?).to be_truthy 
end 

この例では、実際に検証が行われていません。モデルのバリデーションをコメントアウトすると、それは引き続き通過します。

いくつかのヒントモデルの検証をテスト:

  • は工場の使用は避けてください。 .newとテスト対象の属性で初期化するだけです。
  • 無効な入力と有効な入力の両方をテストします。
  • 検証の動作を記述します。
  • 各検証を単独でテストします。統合と機能仕様では通常、検証全体をカバーします。

RSpec.describe Foo do 
    describe "validations" do 
    describe 'x' do 
     it "validates that x is a number between 1 and 10" do 
     expect(Foo.new(500).valid?.errors[:x]).to include "must be less than or equal to 10". 
     expect(Foo.new(10).valid?.errors).to_not have_key :x 
     end 
    end 

    describe 'y' do 
     it "validates that y is a number that is less than 15" do 
     expect(Foo.new(500).valid?.errors[:y]).to include "must be less than 15". 
     expect(Foo.new(10).valid?.errors).to_not have_key :y 
     end 
    end 
    end 
end 
+0

それからそれを乾かしたいならば、これをはるかに流暢にする 'shoulda-matchers'を見てください。 – max

+0

ああ、興味深い - 私はいつも有効なレコードをチェックしていた。したがって、後でフィールドyを追加すると、レコードを有効にして、古いテストにyを追加する必要がありました。私はあなたの例で見ることができますそれぞれは、他の人を心配することなく、テストしているフィールドだけに焦点を当てています。 –

+0

私のテストはドライのままで、私は正しいことをテストすることに集中していなかったので、私はこの回答を好む。ありがとう! –

2

一般的に、私は小さな独立したテストをすることがDRYよりも重要だと思います。

しかし、テストのロジックに矛盾があるようです。

xがゼロのときにfooがの場合は常にとなり、y値を最初の仕様にドロップできるはずです。

it 'is valid when x is zero' do 
    foo = build(:foo, x: 0) 
    expect(foo.valid?).to be_truthy 
end 

とYが10のときのfoo は常に有効な場合は、その後、あなたはその仕様でxの値をドロップすることができるはずです。

it 'is valid when y is ten' do 
    foo = build(:foo, y: 10) 
    expect(foo.valid?).to be_truthy 
end 

これに該当しない場合、あなたはより具体的に例をテストすることを検討してください。例えば

it 'allows x to equal zero' do 
    foo = build(:foo, x: 0) 
    foo.valid? 
    expect(foo.errors).to_not have_key(:x) 
end 

it 'allows y to be ten' do 
    foo = build(:foo, y: 10) 
    foo.valid? 
    expect(foo.errors).to_not have_key(:y) 
end 
1

はい、そのOKが重複テストを維持する場合があります。

DRYコードの習慣の背後にあるルールは、それほど高速ではなく、よりヒューリスティックです。コードDRYを維持する主な目的の1つは、主にメンテナンスのためです。いつか自分自身を繰り返すことを避けるために、あなたがどこにいても繰り返されていないことを保証しようとしていると感じる人もいます。あなたが一度だけ何かを書くために過度の複雑さを加えていることがわかったら(私はSandy Metzからの言葉が好きではありません)、あなたは自分自身に "これは本当に努力の価値がありますか?私のコードをもう読めるか保守可能にするのか? "あなたが書いた重複したコードのインスタンスが異なる理由で書かれているかどうかは、このインスタンスが結果のための副作用のためであるかのように、私は良いリトマスであると思います。

+2

もう一つ、Jay Fields氏が「テスト(とDSL)はDRAMP(記述的で意味のあるフレーズ)ではなくDAMPでなければならない」と思います。 –

+0

これは非常に参考になるアドバイスです。テストは回帰を防ぐだけでなく、コードを分離した状態に保つだけでなく、ドキュメントとしても役立ちます。私はDAMPを念頭に置いていきます。 –

関連する問題