0

私の Rails モデル: タスク has_many の位置。

シナリオ: 新しいポジションを作成すると、それ自体がタスクになるはずです。私はそれをテストしたいと思います、そして私はこのようにしています:

context "creating a new position" do
  let(:position) { create :position, name: 'Read some books', :task => nil }

  it "should create a simple task" do
    Task.find_by_name('Read some books').should be_nil # First should
    position # Execute let() block (FactoryGirl is lazy evaluating)
    Task.find_by_name('Read some books').should_not be_nil # Second (more relevant) should
  end
end

では、テストを改善するにはどうすればよいでしょうか。最初の「すべき」は、タスクがまだ存在しないことを確認するだけなので、ポジションを作成するとタスクが作成されることを確認できます。しかし、これは「ブロックごとに 1 つのみ」という原則に違反しています。それで、これはどうですか?

context "creating a new position" do
  let(:position) do
    position = create :position, name: 'Read some books', :task => nil
    Task.delete_all
    position
  end

  it "should create a simple task" do
    position # Execute let() block (FactoryGirl is lazy evaluating)
    Task.find_by_name('Read some books').should_not be_nil
  end
end

それとも、とにかくそのようなタスクがあってはならないという事実を単純に当てにする必要がありますか (クリーンなテスト データベースにはタスクがないため)。ご意見ありがとうございます。

更新 (解決策)

いくつかの調査の後change、RSpec のマッチャーを見つけました。

let(:position) { create :position, name: 'Read some books', :task => nil }

it "should create a simple task" do
  # Thanks to FactoryGirl's lazy evaluation of let(), the position doesn't yet exist in the first place, and then after calling position in the expect{} block, it is created.
  expect { position }.to change{ Task.count(conditions: { name: 'Read some books' }) }.by(1)
end
4

2 に答える 2

1

何をテストするか

テスト自体がある程度役立つかどうかについては、詳しく説明しません。私には、それらはアプリケーション ロジックではなく、基本的なデータベース機能を実行しているように見えますが、これは実用性がほとんどありませんが、実際にテストすることが重要なことを決定できるのはあなただけです。

具体的に

あなたが与えた例では、変数を記憶する let ブロックを使用する本当の理由はありません。レコードが必要なテストが 1 つだけの場合は、その特定のテストでインスタンス化します。例えば:

context 'creating a new position' do
  it 'should be nil when the position record is missing' do
    Task.find_by_name('Read some books').should be_nil
  end

  it 'should successfully create a position' do
    create :position, name: 'Read some books', :task => nil
    Task.find_by_name('Read some books').should_not be_nil
  end
end

または、レコードが欠落しているときにアプリケーションがどのように動作するかをテストしようとしている場合は、先に進んで変数をメモ化するか、before ブロックでレコードを作成しますが、その特定の test でレコードを明示的に削除します。

複数のコンテキスト

最後に、個々のテストで設定するには状態が多すぎることに気付いた場合、それは通常、テストを異なるコンテキストに分割することを検討すべき手がかりです。たとえば、テストを、レコードが存在しない場合の動作をチェックする 1 つのコンテキストと、レコード存在する場合の別のコンテキストに分けたい場合があります。

すべてのテストと同様に、これは科学というより芸術です。あなたのマイレージは異なる場合があります。

于 2012-07-15T17:20:44.630 に答える
0

RSpec 2.11では、 にブロックを渡すことができ、ブロックchangeの戻り値が変更されるものであると想定されます。私はこれがあなたのために働くことを期待します:

expect { position }.to change { Task.where(:name => 'Read some books').count }.from(0).to(1)
于 2012-07-15T17:19:09.357 に答える