Câu hỏi Làm thế nào để chuyển một biến mẫu tới một ví dụ được chia sẻ RSpec


Tôi đang sử dụng RSpec (2.10.1) để kiểm tra tính hợp lệ trên một 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. Các xác nhận đầu tiên được viết trên bảng công ty, do đó, mã trông như thế này:

# 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à cách 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ố cho ví dụ được chia sẻ để 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à cách 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 để tôi có được một cái gì đó như thế này để làm việc?


35
2017-07-06 01:33


gốc




Các câu trả lời:


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

Tôi khuyên bạn nên sử dụng let cho những 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

52
2017-07-06 06:11



Một số phần không hợp lý với tôi. Nếu đó là self khác nhau, 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() với @company (giữ 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 lên đến do). - George Shaw
Có hai giá trị cơ bản self tiếp tục trong RSpec, và nó tương tự với hai giá trị của self trong định nghĩa lớp ruby. Giữa một describe/context/shared_examples_for và tương ứng của nó end (nhưng không phải trong it khối), self là nhóm ví dụ - giống như self trong một 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 it/let khối hoặc một before/after/around móc 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. - Myron Marston
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 lồng nhau describe/context/shared_examples_for các khối để xác định tất cả các ví dụ; tạ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 xác định ( it khối). 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ụ. - Myron Marston
Cảm ơn. Tôi khá mới với RSpec, nhưng tôi thấy hành vi này có mùi hôi. Tác dụng phụ của việc thực hiện không nên cản trở các lập trình viên. Việc thêm let () phá hủy sự đồng nhất của các tham số trên dòng. Dường như nếu RSPec không tìm thấy một biến xác định trong phạm vi it-self sau đó nó nên tìm trong phạm vi describe-self. Hoặc, phải có một cái gì đó để có được các biến từ bản thân khác (tức là otherself.company). Mã của tôi sử dụng subject(@company)và tôi đã tìm thấy rằng tôi chỉ có thể sử dụng subject thay thế model, mặc dù nó có mùi mã của riêng nó. - George Shaw
Đó không phải là cách tôi đọc câu hỏi, nhưng đây là cách bạn có thể chuyển nó thành before chặn hoặc vào let bên trong Company nhóm ví dụ: gist.github.com/myronmarston/4986865. Tôi vẫn có khuynh hướng ủng hộ let phương thức trên các biến mẫu cho các trường hợp như thế này, bởi vì các biến cá thể biến thành sự tồn tại khi được tham chiếu, đó là nguyên nhân gây ra vấn đề của poster ban đầu: @company các biến trong các ví dụ là riêng biệt (một trong số đó là nil) nhưng điều đó không rõ ràng. - Myron Marston