2015-12-21 94 views
0

我使用Rspec和fixtures來測試Rails模型。使用Fixtures在rspec測試中刪除重複的代碼

一些測試用例有非常相似的代碼看起來像這樣

it 'creates request' do 
    u = users(:user_one) 
    o = documents(:document_one) 
    requests = Request.where(status: Request::PENDING, user: u, document: o) 
    expect { o.request_access(u) }.to change { requests.count }.by(1)  
end 

it 'does not create a request if user already has access' do 
    u = users(:user_one) 
    o = documents(:document_one) 
    Request.create status: Request::ACCEPTED, user: u, document: 0 
    requests = Request.where(status: Request::PENDING, user: u, document: o) 
    expect { o.request_access(u) }.not_to change { requests.count }  
end 

我怎麼能消除這裏代碼重複?有沒有辦法使用let來解決問題?如果我有更多的測試用例,其中使用了其他固件,那麼Request.where(status: Request::PENDING, user: u, document: o)是指其他對象呢?

回答

4

這應該是乾的不夠。 let所有的事情!

let(:user) { users(:user_one) } 
let(:document) { documents(:document_one) } 
let(:requests) { Request.where(status: Request::PENDING, user: user, document: document) } 
let(:action) { document.request_access(user) } 

context 'user does not have access' do 
    it 'creates request' do 
    expect { action }.to change { requests.count }.by(1)  
    end 
end 

context 'user has approved access' do 
    before do 
    Request.create status: Request::ACCEPTED, user: user, document: document 
    end 

    it 'does not create a request' do 
    expect { action }.not_to change { requests.count }  
    end 
end 
+0

偉大,謝謝。出於某種原因,我相信你不能在其他'let'塊中使用'let'塊。使用'subject'作爲':action'也不是更清楚嗎? –

+0

@ S.S.J:不知道。從不喜歡'主題'。此外,它暗示了一些對象,而在這裏我們有一個行動。但無論你想要什麼都可以命名。 :) –

+0

樣式不同,但除非您正在編寫共享方法,否則使用明確的「主題」通常是不鼓勵的。理想情況下,從閱讀測試中可以明顯看出這個問題。 – zetetic

1

你可以使用letbefore(:each)

before(:each) do 
    @u = users(:user_one) 
    @o = documents(:document_one) 
end 

it 'creates request' do 
    requests = Request.where(status: Request::PENDING, user: @u, document: @o) 
    expect { @o.request_access(@u) }.to change { requests.count }.by(1)  
end 

it 'does not create a request if user already has access' do 
    Request.create status: Request::ACCEPTED, user: @u, document: @o 
    requests = Request.where(status: Request::PENDING, user: @u, document: @o) 
    expect { @o.request_access(@u) }.not_to change { requests.count }  
end 

let(:u) { users(:user_one) } 
let(:o) { documents(:document_one) } 

it 'creates request' do 
    requests = Request.where(status: Request::PENDING, user: u, document: o) 
    expect { o.request_access(u) }.to change { requests.count }.by(1)  
end 

it 'does not create a request if user already has access' do 
    Request.create status: Request::ACCEPTED, user: u, document: o 
    requests = Request.where(status: Request::PENDING, user: u, document: o) 
    expect { o.request_access(u) }.not_to change { requests.count }  
end 

編輯:您不能requests查詢過濾器之前添加到,因爲你之前有Request.create你在第二個測試中查詢。無論如何,要幹它,你可以創建一個方法,返回查詢:

let(:u) { users(:user_one) } 
let(:o) { documents(:document_one) } 

it 'creates request' do 
    requests 
    expect { o.request_access(u) }.to change { requests.count }.by(1)  
end 

it 'does not create a request if user already has access' do 
    Request.create status: Request::ACCEPTED, user: u, document: o 
    requests 
    expect { o.request_access(u) }.not_to change { requests.count }  
end 

def requests 
    Request.where(status: Request::PENDING, user: u, document: o) 
end 
+0

我真的很想刪除'request = Request.where(status:Request :: PENDING,user:u,document:o)'。有沒有辦法做到這一點? –

+0

問題是你需要在請求查詢之前調用'Request.create',所以你不能將它添加到'before(:each)'...請注意我編輯的答案 – gabrielhilal

+0

如果你有' Request.create'在before操作中會在兩個測試中運行。所以,你的第一次測試會失敗,除非你把測試包裝在像Sergio回答 – gabrielhilal