2012-07-06 5 views
35

Tôi đang sử dụng RSpec (2.10.1) để kiểm tra tính hợp lệ trên mô hình và đã trích xuất một số mã để chia sẻ với các xác thực mô hình khác. Kiểm chứng thực đầu tiên được viết trên bảng công ty, do đó mã trông như thế này:Cách chuyển một biến mẫu tới ví dụ chia sẻ RSpec

# support/shared_examples.rb 
shared_examples "a text field" do |field, fill, length| 
    it "it should be long enough" do 
    @company.send("#{field}=", fill * length) 
    @company.should be_valid 
    end 

    etc... 
end 

và việc sử dụng là:

# company_spec.rb 
describe Company do 
    before { @company = Company.new(init stuff here) } 

    describe "when address2" do 
    it_behaves_like "a text field", "address2", "a", Company.address2.limit 
    end 

    etc... 
end 

Tôi muốn vượt qua @company như một tham số để chia sẻ Ví dụ để tôi có thể sử dụng lại mã cho các mô hình khác nhau, một cái gì đó như thế này:

# support/shared_examples.rb 
shared_examples "a text field" do |model, field, fill, length| 
    it "it should be long enough" do 
    model.send("#{field}=", fill * length) 
    model.should be_valid 
    end 

    etc... 
end 

và việc sử dụng là:

# company_spec.rb 
describe Company do 
    before { @company = Company.new(init stuff here) } 

    describe "when address2" do 
    it_behaves_like "a text field", @company, "address2", "a", Company.address2.limit 
    end 

    etc... 
end 

Tuy nhiên, khi tôi làm điều này, tôi nhận được undefined method 'address2' for nil:NilClass. Nó xuất hiện @company không được thông qua (không phải trong phạm vi?) Làm thế nào để có được một cái gì đó như thế này để làm việc?

Trả lời

49

Vấn đề là self trong nhóm ví dụ khác với self trong móc before, vì vậy nó không phải là cùng một biến mẫu mặc dù nó có cùng tên.

tôi khuyên bạn nên sử dụng let đối với trường hợp như thế này:

# support/shared_examples.rb 
shared_examples "a text field" do |field, fill, length| 
    it "it should be long enough" do 
    model.send("#{field}=", fill * length) 
    model.should be_valid 
    end 
end 

# company_spec.rb 
describe Company do 
    describe "when address2" do 
    it_behaves_like "a text field", "address2", "a", Company.address2.limit do 
     let(:model) { Company.new(init stuff here) } 
    end 
    end 
end 
+1

Một số mảnh không có ý nghĩa đối với tôi. Nếu đó là 'self' thì khác, nó khác ở đâu? Tại sao '@ company.send()' và '@ company.should' làm việc trong' shared_examples'? Trong đề nghị của bạn, tôi có thể thay thế 'Company.new()' bằng '@ company' (giữ khối' before') và nó hoạt động. Sự hiểu biết của tôi là thiếu một cái gì đó về những gì chính xác đang xảy ra ở đây. Có vẻ như 'self' chỉ khác nhau ở một nơi cụ thể (dòng 'it_behaves_like' tối đa' do'). –

+6

Có hai giá trị cơ bản 'self' thực hiện trong RSpec, và nó tương tự với hai giá trị của self trong định nghĩa lớp ruby. Giữa 'description' /' context'/'shared_examples_for' và' end' tương ứng của nó (nhưng không nằm trong 'nó' blocks),' self' là nhóm ví dụ - giống như 'self' trong thân lớp (nhưng không phải trong định nghĩa phương thức) là chính lớp đó. 'self' trong một khối' it'/'let' hoặc' before'/'after' /' around' hook hoặc là ví dụ - giống như 'self' trong định nghĩa phương thức cá thể của lớp là cá thể của lớp . –

+3

Một cách khác để nghĩ về nó: có một quá trình hai vượt qua mà RSpec thực hiện. Đầu tiên, nó đánh giá tất cả các khối 'describe' /' context'/'shared_examples_for' lồng nhau để xác định tất cả các ví dụ; tại thời điểm này, 'self' trong các ngữ cảnh này là nhóm ví dụ tương ứng. Thứ hai, RSpec chạy tất cả các ví dụ được định nghĩa (các khối 'nó'). Mỗi ví dụ được định nghĩa được đánh giá trong một cá thể của nhóm ví dụ tương ứng và 'self' là ví dụ. –