2016-07-27 10 views
1

私は質問をうまく表現できない場合は、正しいものを入力してください。rspec単体テストで期待通りの模擬選択

次のコードを想定します。次のようにメソッドをテストすることはもちろん可能である

class Filters 
    def self.good ducks 
    ducks.select(&:good?) 
    end 
end 

を:

describe Filters, '#good' do 
    let(:good) { double(:good, good?: true) } 
    let(:bad) { double(:bad, good?: false) } 

    subject { Filters.good(ducks) } 

    context 'none' do 
    let(:ducks) { [] } 
    it { is_expected.to eq [] } 
    end 

    context 'one good' do 
    let(:ducks) { [good] } 
    it { is_expected.to eq [good] } 
    end 

    context 'one bad' do 
    let(:ducks) { [bad] } 
    it { is_expected.to eq [] } 
    end 

    context 'one good and one bad' do 
    let(:ducks) { [good, bad] } 
    it { is_expected.to eq [good] } 
    end 

    context 'some good and some bad' do 
    let(:ducks) { [good, bad, bad, good, bad, good] } 
    it { is_expected.to eq [good, good, good] } 
    end 
end 

しかし、(もちろんありません、実際にすべてが、どれも例すべてを列挙/真/偽の組み合わせのための1つ/いくつか/多くの)私は実際にはユニットの方法をテストして感じていませんの統合私は私のgoodメソッドに "リーク"の動作の知識のチンのselectテストケースの数を掛ける原因となります。ある意味で私のテストケースはselectメソッドの動作をテストしています。

私には、代わりに、模擬を使用して(テストではなく、チェックで)、メソッドが正しくデリゲートするようにすることが適切です。自分が書いた関数と一体化していれば、できることだ。例と同様のものexpect(obj).to receive(:foo).with(:bar)と言うことができます。

以下の例は機能しませんが、すべてのケースを列挙するのではなく、何をしたいのかという考えを伝えると思います。

describe Filters, '#good' do 
    it 'returns only good ones' do 
    ducks = double(:ducks) 
    expect(ducks).to receive(:filter).with(:good?).and_return(:filtered) 
    expect(Filters.good(ducks).to eq) 
    end 
end 

の例では、引数が、それは役に立たない方法であることを言うとFilter.goodのユーザーは単に直接、select -statementを移動するだけで必要性を移動させているという事実を考慮してくださいselectを使用することを避けるために、とても些細に見えるかもしれません別の場所へのテストのために。

私はここで何か基本的なことを誤解しているか見落としていますか?

Ps 1.簡潔さのためにいくつかのテストケースを無視しています。

Psの2.私はユニットない統合の必要性を強調していた理由のショートバージョンがテストはこのビデオである:https://www.youtube.com/watch?v=VDfX44fZoMc

編集: この質問フレーズに良い方法はおそらくだろう:最初のテストは、古典主義者がどのようにしてFilters.goodをテストするかの要点の例ですが、モチストはどのようにテストしますか?

+0

ソリューションを見つけましたか? –

+0

@PaulFioravanti提供していただきありがとうございます。しかし、私にはまだ解決策がないようです。私は質問に明確化を加えています。 – chris

答えて

0

私はあなたが達成しようとしていることを100%確信していませんが、私は工場の女の子、特に工場の女の子のcreate_listを調べます。それを悪いものに変更する。 https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md あなたが本当に望んでいれば、それぞれが持っていると期待できる:良い?それを求めた。 最後のリストに良いリストしかないことを確認するほうがいいかもしれません。 あなたのやっていることが役に立つかもしれない現実世界の例を挙げていますが、工場の女の子リストを作成することは、あなたの問題の少なくとも1つを満たしてくれると思います。

更新:

let(:duck){double :duck} 
describe Filters, '#good' do 
    it 'returns only good ones' do 
    ducks = [duck, duck, duck] 
    expect(ducks).to receive(:good).exactly(3).times 
    Filters.good(ducks) 
    end 
end 
+0

ありがとうございます。私は質問を言い換えて、例を追加しました。 – chris

+0

[OK]を私の答えを変更します:P – stephenlloyd

0

テスト対象のメソッドは、フィルタリングを行うので、私はあなたがでgood?の応答は別に(メソッドで任意のコードをスタブを必要とせずに書かれた簡潔な単一のユニットテストを得ることができると思いますあなたの結果内のオブジェクトを含める(またはその欠如のためにテストすることによってで渡されるコレクションの任意の要素は))セット:

class Filters 
    def self.good(ducks) 
    ducks.select(&:good?) 
    end 
end 

RSpec.describe Filters do 
    describe '.good' do 
    let(:good_duck) { double(:good, good?: true) } 
    let(:bad_duck) { double(:bad, good?: false) } 
    let(:ducks) { [good_duck, bad_duck] } 
    let(:good) { described_class.good(ducks) } 

    it 'returns only good ducks' do 
     expect(good).to include(good_duck) 
     expect(good).not_to include(bad_duck) 
    end 
    end 
end 

スペックはしているどのように多くの良いか悪いアヒル気にしませんthに渡されるコレクションe Filters.goodメソッド:good?に応答するオブジェクトがtrueであることのみが結果セットに含まれ、falseで応答するオブジェクトはありません。contextのブロックは不要です空の配列をテストします。

+0

しかし、これは実装に誤った肯定を与えるでしょう: '[ducks.first]'、複数のケースをテストする必要性を再度示唆します。 – chris

+0

@chris申し訳ありませんが、私はあなたが「実装にとって偽陽性であるということを理解していません: '[ducks.first]' "。コレクションの最初の要素を持つ配列はどこにあるのですか? –

+0

'Filters.good(ducks)'の実装が '[ducks.first]'の場合、テストは(誤って)合格します。 – chris

関連する問題