2016-10-14 46 views
4

所以在我的不斷髮展rspecs對我的回報率模型,我結束了兩個測試如出一轍:保持乾燥,但要重複用於不同的原因

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

這出現,因爲我寫的規格進行驗證首先x,然後爲y添加規範。

顯然,重構的時間。我可以刪除其中一個規格,因爲它們是重複的:保持乾燥。

現在,每個規格的內部可能完全相同,但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 

但在我看來,我現在有一個規範是測試兩件事情(在富模型兩種驗證條款)。這也不好,無論如何。有潛伏的氣味。

是否有另一種方法我錯過了?

+0

完全可以有兩個測試恕我直言 –

+0

這要看情況。第一次測試是否應該通過'y:nil'? 'y:false'?與'y:MyY.new'?如果沒有,你已經陷入困境。人們應該想要什麼正在測試。我會用4個測試來處理'{x,y}∈[good,bad]'。 – 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更重要。

但是,您的測試邏輯似乎存在不一致。

如果foo爲總是當x爲零時有效,那麼您應該可以在第一個規格中刪除y值。

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

如果富總是當y爲十,那麼你應該能夠在規範下降的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

是的,有情況下,其確定保留重複試驗。

DRY代碼實踐背後的規則並不難,也更加具有啓發性。保持代碼DRY的主要目的之一是主要用於維護目的。有時候人們(包括我自己)會覺得你正在努力確保你不會爲了不重複自己而在任何地方重複自己。如果你發現你爲了只寫一些東西而增加了不必要的複雜性(我喜歡Sandy Metz的話:「不那麼幹它」),那麼你需要問自己:「這真的值得嗎?」「這是否讓我的代碼變得可讀或可維護?「。一個我認爲是好的試驗是無論您是否寫過重複代碼的實例都是由於不同的原因編寫的,就像這個實例是爲了這個實例的結果副作用一樣。

+2

還有一個,我認爲Jay Fields說:「測試(和DSL)應該是DAMP,而不是DRY(描述性和有意義的短語)」。 –

+0

嗯,這是非常有用的建議,測試不僅僅是防止迴歸和保持你的代碼解耦,他們也應該作爲文檔。我會記住DAMP。 –

相關問題