2016-07-27 98 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 

但枚舉所有的情況下(當然不是真正所有,但無/一個/一些/許多組合的真/假good狀態)讓我覺得我其實不是單元測試方法,但集成測試它,因爲我讓將知識select的行爲知識泄露到我的good方法中,導致測試用例的數量增加。從某種意義上說,我的測試用例正在測試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,請考慮的是,移動select語句來僅移動需要測試到另一個位置。

我是否誤解或忽略了一些根本性的東西?

ps 1.爲了簡潔起見,我忽略了一些測試用例。

詩篇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 如果你真的想要可以期待每個人都有:好?呼籲它。 只是爲了確保你的列表最後只有好的列表。 給你一個真實世界的例子,你可能會做些什麼,但我認爲創建一個工廠女孩名單將至少滿足你的一個問題。

修改:

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

好吧,我會修改我的答案: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塊,但可能除了context測試一個空數組。

+0

但是這會給執行造成誤判:'[ducks.first]',這將再次表明需要測試多個案例。 – chris

+0

@chris對不起,我不明白你的意思是「執行的誤判:'[ducks.first]'」。帶有集合的第一個元素的數組在哪裏起作用? –

+0

如果'Filters.good(ducks)'的實現是'[ducks.first]',則測試通過(錯誤地)。 – chris