1

我有三個型號:RSpec的沒有看到改變的ActiveRecord對象與`變化(對象:消息)`語法

  • User
  • Company
  • Commitment

Commitment是HABTM連接表UsersCompaniesUser加入Company時,它會創建一個新的Commitment)。它也有一些額外的列/屬性:

  • admin(沒有用戶具有管理員權限查看這家公司?)
  • confirmed_by_admin(已經公司管理員證實了這一點用戶的請求加入公司?)
  • confirmed_by_member(有本人確認的邀請加入該公司的用戶?)

我還定義了一個方便的方法來快速確定是否承諾完全證實:

class Commitment < ApplicationRecord 
    def confirmed? 
    confirmed_by_admin? && confirmed_by_member? 
    end 
end 

現在我正在寫一個要求規範,但由於某些原因,change匹配唯一擁有兩種語法的作品之一:

let :carol { FactoryGirl.create(:user) } 
let :company { FactoryGirl.create(:company) } 

it 'confirms invitation to join company' do 
    # Initialize unconfirmed commitment 
    FactoryGirl.create(:commitment, user: carol, 
            company: company, 
            confirmed_by_admin: true) 

    expect do 
    patch commitment_path(carol.commitments.first), 
      params: { commitment: { confirmed_by_member: true } } 

    # for the following syntaxes, ------------------------------------------------ 
    # this works: 
    end.to change { carol.commitments.first.confirmed?) }.from(false).to(true) 
    # and this fails: 
    end.to change(carol.commitments.first, :confirmed?).from(false).to(true) 
    # ---------------------------------------------------------------------------- 

end 

看來,carol.commitments.first沒有被加載時的RSpec測試的變化 - 我得到以下測試輸出:

Failure/Error: 
    expect do 
    patch commitment_path(carol.commitments.first), 
      params: { commitment: { confirmed_by_member: true } } 
    end.to change(Commitment.find_by(user: carol, company: company), :confirmed?).from(false).to(true) 

    expected #confirmed? to have changed from false to true, but did not change 
# ./spec/requests/commitments_spec.rb:69:in `block (3 levels) in <top (required)>' 

什麼給?顯然,我可以堅持花括號/塊的語法,但我想了解爲什麼一個工作,而不是其他。

回答

2

在檢查docs和嘗試自己一個新的Rails項目複製的情況下,也失敗了,我相信就是爲什麼它是失敗的原因是因爲

  • .change的「塊」的形式(該expect塊「之後」,「之前」和)是跑了兩次,無論是塊內:

    .change{ carol.commitments.first.confirmed? }

  • .change的「方法」形式對第一個參數運行一次:carol.commitments.first,但爲第二個參數:confirmed?運行兩次。但是,問題在於spec文件中此刻的carol.commitments.first與您在commitments_controller#update(最有可能該對象名爲@commitment)中實際更新的對象沒有共享相同的內存空間。雖然它們與記錄相同,但它們是單獨的實例,另一個實例的屬性值不會在另一個實例發生更改時自動更改。

考慮這表明在這個「法」的形式工作的情況如下:

it 'sometest' do 
    commitment = FactoryGirl.create(:commitment, user: carol, 
            company: company, 
            confirmed_by_admin: true) 
    expect do 
    # this commitment object is exactly the same object passed in the `change` below 
    commitment.confirmed_by_member = true 
    end.to change(commitment, :confirmed?).from(false).to(true) 
end 

免責聲明:這是未經證實的,但因爲它太複雜,我寫的評論(與所有的樣本測試代碼),我在這裏寫下它作爲答案。如果有人知道更好,請讓我知道。

+0

是的,我認爲就是這樣。 –

+0

這似乎是最可能的解釋 - 「更改」匹配器不會在「expect」塊完成後重新加載傳遞給它的ActiveRecord對象。我將在GitHub上提交一個問題,以便仔細檢查,但我已經準備好將其解決,除非其他人有更多的可驗證的洞察力。 –

+0

感謝您的反饋!很高興知道你們也認爲相同:) –