2017-09-21 20 views
0

我想測試一個使用ActiveRecord適量的方法。我一直聽說單元測試方法,而不是使用數據庫是最好的方法。然而,這對我來說的缺點是如果你錯誤地存活了ActiveRecord的響應呢?我可能會錯誤地將任何ActiveRecord在現實中返回的內容剔除,現在我的測試不準確。單元測試具有兩個數據庫查詢的方法。我應該剔除數據庫調用嗎? Rails/Rspec

FYI一個user有許多coupons和(當它應用於order的次)coupon可以有很多coupon_uses

這是我的方法:

def get_coupons_and_uses_for_user 
     coupons = Promotions::Coupon 
     .includes(:coupon_uses) 
     .where(user_id: user_id) 

     coupons.reduce([]) do |memo, c| 
     memo << { coupon: c, coupon_uses: c.coupon_uses.order('created_at desc') } 
     end 
    end 

上述方法(這基本上查詢用戶的優惠券,然後返回其使用相關聯的每個優惠券)有兩個ActiveRecord的要求,這兩者我需要的,如果存根出我沒有在我的測試中使用一個數據庫:

Promotions::Coupon.includes(:coupon_uses).where(user_id: user_id)

c.coupon_uses.order('created_at desc') #The .order causes ActiveRecord to hit the database

這裏我的測試:

describe "#get_coupons_and_uses_for_user" do 
    subject { service_instance.get_coupons_and_uses_for_user } 

    let(:service_instance) { described_class.new(user_id) } 
    let(:user_id) { 1 } 
    let(:coupon1) { build_stubbed(:coupon) } 
    let(:coupon2) { build_stubbed(:coupon) } 
    let(:coupons) { [coupon1, coupon2] } 
    let!(:coupon_use1) { build_stubbed(:coupon_use) } 
    let!(:coupon_use2) { build_stubbed(:coupon_use) } 
    let!(:coupon_use3) { build_stubbed(:coupon_use) } 
    let!(:coupon_use4) { build_stubbed(:coupon_use) } 

    before do 
     allow(Promotions::Coupon).to receive_message_chain(:includes, :where) { coupons } 
     allow(coupon1).to receive_message_chain(:coupon_uses, :order) { [coupon_use1, coupon_use2] } 
     allow(coupon2).to receive_message_chain(:coupon_uses, :order) { [coupon_use3, coupon_use4] } 
    end 

    it "returns the user's coupons associated with their coupon uses" do 
     expect(subject).to eq(
     [ 
      { 
      coupon: coupon1, 
      coupon_uses: [coupon_use1, coupon_use2] 
      }, 
      { 
      coupon: coupon2, 
      coupon_uses: [coupon_use3, coupon_use4] 
      } 
     ] 
    ) 
    end 
    end 

這是測試的好辦法?或者我應該使用數據庫?爲什麼或者爲什麼不?

這裏的問題是,我碰傷了我的ActiveRecord的返回值調用是這樣的:

allow(coupon1).to receive_message_chain(:coupon_uses, :order) { [coupon_use1, coupon_use2] } 

但是,如果我錯了,什麼該查詢返回(想象一下,如果查詢較多什麼複雜)。這是一個有效的關注嗎?

+0

可能的重複[測試方法是大量的數據庫查詢。單元測試可以嗎?](https://stackoverflow.com/questions/46332283/testing-methods-were-lots-of-database-queries-in-them-is-it-okay-to-unit-test ) – jvillian

回答

0

不,不要將呼叫存根到數據庫。

Rails約定是在模型測試中使用數據庫。無論好壞,這都是Rails項目所期望的。

你不必遵循約定,但它會讓你的生活更輕鬆。所以除非你有強制性的理由這樣做,否則我會避免它。


爲什麼遵循這個約定?對DB運行模型試驗的慣例是好幾個原因:

  1. 開發者熟悉Rails可以起牀快,加快該項目時,它遵循約定(在這種情況下,他們可以調試/寫測試以熟悉的方式工作)

  2. 如果數據庫在測試中速度較慢,則生產速度可能會很慢,這將鼓勵您在開發過程中提供反饋,從而鼓勵良好的數據庫設計。

  3. 代碼較少。將所有來自ActiveRecord模型的調用都保存到數據庫中會變得麻煩,這使得重構更多的工作來在更改對ActiveRecord的調用時更新所有的方法存根。

  4. 當您升級Rails時,ActiveRecord的接口可能會更改,但存根不會。因此,在生產中對數據庫運行時,您的測試可能會失敗。

+0

但爲什麼會議在這裏好?爲什麼它會讓事情變得更簡單?如果遵循極端的話......從長遠來看,我只會有很多較慢的測試。 – Jwan622

+0

其他人都在關心?這些測試真的是集成測試嗎? – Jwan622

+1

遵循@ csexton的建議,甚至沒有升級Rails,但是例行的數據庫遷移可能會導致代碼崩潰。 存根調用可能會錯誤地讓規範通過,因爲他們對db的看法已經過時。 此外,根據定義ActiveRecord綁定到數據庫。所以我仍然認爲它是ActiveRecord上下文中的單元測試。大多數情況下,我們假設AR起作用。我們不打算寫一個AR規範,它也運行原始SQL查詢來檢查數據是否實際在數據庫中。 –