Cách kiểm tra mối quan tâm trong Rails


104

Cho rằng tôi có một Personablemối quan tâm trong ứng dụng Rails 4 của tôi có một full_namephương pháp, tôi sẽ kiểm tra điều này bằng cách sử dụng RSpec như thế nào?

lo ngại / persible.rb

module Personable
  extend ActiveSupport::Concern

  def full_name
    "#{first_name} #{last_name}"
  end
end

Bạn đang sử dụng khung thử nghiệm nào? Cũng nên nhớ Persbing chỉ là một mô-đun Ruby bình thường. Kiểm tra nó giống như bạn kiểm tra bất kỳ loại mixin nào khác.
Lee Jarvis

Vẫn chưa ActiveSupport::Concernđược đưa ra khỏi Rails? Tôi nghĩ rằng nó đã xảy ra một chút trước đây.
Russell

@LeeJarvis Tôi đang sử dụng Rspec cùng với w / FactoryGirl
Kyle Decot


4
@Russell Tôi đồng ý. Điều đó nói rằng, tôi sẽ không giúp ai đó giải đáp thắc mắc của họ chỉ vì họ đang làm theo cách Rails-y làm điều gì đó mà tôi không đồng ý. Dù sao thì đây là cách thoát khỏi chủ đề của câu hỏi này :-)
Lee Jarvis

Câu trả lời:


176

Phương pháp bạn tìm thấy chắc chắn sẽ hoạt động để kiểm tra một chút chức năng nhưng có vẻ khá mỏng manh — lớp giả của bạn (thực ra chỉ là một Structgiải pháp của bạn) có thể hoạt động như một lớp thực mà includebạn quan tâm. Ngoài ra, nếu bạn đang cố gắng kiểm tra các mối quan tâm về mô hình, bạn sẽ không thể làm những việc như kiểm tra tính hợp lệ của các đối tượng hoặc gọi ra lệnh gọi lại ActiveRecord trừ khi bạn thiết lập cơ sở dữ liệu tương ứng (vì lớp giả của bạn sẽ không có bảng cơ sở dữ liệu sao lưu nó). Hơn nữa, bạn sẽ không chỉ muốn kiểm tra mối quan tâm mà còn muốn kiểm tra hành vi của mối quan tâm bên trong thông số kỹ thuật mô hình của bạn.

Vậy tại sao không giết hai con chim bằng một viên đá? Bằng cách sử dụng các nhóm ví dụ được chia sẻ của RSpec , bạn có thể kiểm tra mối quan tâm của mình đối với các lớp thực tế sử dụng chúng (ví dụ: mô hình) bạn sẽ có thể kiểm tra chúng ở mọi nơi chúng được sử dụng. Và bạn chỉ phải viết các bài kiểm tra một lần và sau đó chỉ cần đưa chúng vào bất kỳ thông số kỹ thuật nào của mô hình mà bạn quan tâm. Trong trường hợp của bạn, nó có thể trông giống như sau:

# app/models/concerns/personable.rb
module Personable
  extend ActiveSupport::Concern

  def full_name
    "#{first_name} #{last_name}"
  end
end

# spec/concerns/personable_spec.rb
require 'spec_helper'

shared_examples_for "personable" do
  let(:model) { described_class } # the class that includes the concern

  it "has a full name" do
    person = FactoryBot.build(model.to_s.underscore.to_sym, first_name: "Stewart", last_name: "Home")
    expect(person.full_name).to eq("Stewart Home")
  end
end

# spec/models/master_spec.rb
require 'spec_helper'
require Rails.root.join "spec/concerns/personable_spec.rb"

describe Master do
  it_behaves_like "personable"
end

# spec/models/apprentice_spec.rb
require 'spec_helper'

describe Apprentice do
  it_behaves_like "personable"
end

Ưu điểm của cách tiếp cận này thậm chí còn trở nên rõ ràng hơn khi bạn bắt đầu làm những việc mà mình quan tâm như gọi lệnh gọi lại AR, trong đó bất kỳ thứ gì nhỏ hơn đối tượng AR sẽ không làm được.


2
Một bất lợi của điều này là nó sẽ chậm lại parallel_tests. Tôi nghĩ rằng sẽ tốt hơn nếu có các bài kiểm tra riêng biệt thay vì sử dụng shared_examples_forit_behaves_like.
Artem Kalinchuk

6
@ArtemKalinchuk Tôi không chắc điều đó đúng, per github.com/grosser/parallel_tests/issues/168 parallel_tests dựa trên mỗi tệp, vì vậy các ví dụ được chia sẻ sẽ không làm chậm nó. Tôi cũng sẽ tranh luận rằng các hành vi được chia sẻ được nhóm hợp lý sẽ vượt trội hơn tốc độ kiểm tra.
Aaron K

8
Đảm bảo đưa concernsthư mục vào spec_helper.rb github.com/rspec/rspec-core/issues/407#issuecomment-1409871
Ziggy

1
Tôi không thể tìm thấy bất cứ điều gì về việc bao gồm thư mục mối quan tâm trong liên kết đó. Bạn có thể vui lòng làm rõ điều này được thực hiện như thế nào? Tôi không thể nhận được bài kiểm tra RSpec của mình để nhận ra mô-đun trong một trong những mối quan tâm của tôi.
Jake Smith

4
Không thêm _specvào tên tệp chứa shared_examples_for (trong trường hợp này là persible_spec.rb), nếu không bạn sẽ nhận được thông báo cảnh báo gây hiểu lầm - github.com/rspec/rspec-core/issues/828 .
Lalu

62

Đáp lại những nhận xét mà tôi đã nhận được, đây là những gì tôi đã kết thúc (nếu ai có cải tiến, vui lòng đăng chúng) :

spec / lo ngại / persible_spec.rb

require 'spec_helper'

describe Personable do
  let(:test_class) { Struct.new(:first_name, :last_name) { include Personable } }
  let(:personable) { test_class.new("Stewart", "Home") }

  it "has a full_name" do
    expect(personable.full_name).to eq("#{personable.first_name} #{personable.last_name}")
  end
end

1
Có, điều này sẽ phá vỡ các bài kiểm tra khác nếu chúng tình cờ kiểm tra một lớp thực được gọi Person. Tôi sẽ chỉnh sửa để sửa chữa.
Russell

Điều này không hoạt động. Nó mang lại cho tôi lỗi:undefined method 'full_name' for #<struct first_name="Stewart", last_name="Home">
Kyle Decot

Hãy thử bao gồm Persable thay vì mở rộng nó. Tôi sẽ cập nhật câu trả lời.
Russell

Hoạt động tốt ngay bây giờ. Cảm ơn đã chỉ cho tôi đi đúng hướng và giúp tôi Refactor @Russell
Kyle Decot

Hoạt động tuyệt vời và trông đẹp mắt
Edward

7

Một suy nghĩ khác là sử dụng gem with_model để kiểm tra những thứ như thế này. Tôi đang tìm cách tự kiểm tra mối quan tâm và đã thấy viên ngọc pg_search thực hiện điều này . Nó có vẻ tốt hơn nhiều so với thử nghiệm trên các mô hình riêng lẻ, vì chúng có thể thay đổi và thật tuyệt khi xác định những thứ bạn sẽ cần trong thông số kỹ thuật của mình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.