Ruby-on-rails 如何在 Rails 中测试关注点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16525222/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Test a Concern in Rails
提问by Kyle Decot
Given that I have a Personableconcern in my Rails 4 application which has a full_namemethod, how would I go about testing this using RSpec?
鉴于我Personable在 Rails 4 应用程序中有一个问题,它有一个full_name方法,我将如何使用 RSpec 进行测试?
concerns/personable.rb
关注点/personable.rb
module Personable
extend ActiveSupport::Concern
def full_name
"#{first_name} #{last_name}"
end
end
回答by Josh Leitzel
The method you found will certainly work to test a little bit of functionality but seems pretty fragile—your dummy class (actually just a Structin your solution) may or may not behave like a real class that includes your concern. Additionally if you're trying to test model concerns, you won't be able to do things like test the validity of objects or invoke ActiveRecord callbacks unless you set up the database accordingly (because your dummy class won't have a database table backing it). Moreover, you'll want to not only test the concern but also test the concern's behavior inside your model specs.
您找到的方法肯定可以测试一些功能,但看起来非常脆弱——您的虚拟类(实际上只是Struct您的解决方案中的一个)可能会也可能不会表现得像include您关心的真实类。此外,如果您尝试测试模型问题,除非您相应地设置数据库,否则您将无法执行诸如测试对象的有效性或调用 ActiveRecord 回调之类的操作(因为您的虚拟类将没有数据库表支持它)。此外,您不仅要测试关注点,还要在模型规范中测试关注点的行为。
So why not kill two birds with one stone? By using RSpec's shared example groups, you can test your concerns against the actual classes that use them (e.g., models) andyou'll be able to test them everywhere they're used. And you only have to write the tests once and then just include them in any model spec that uses your concern. In your case, this might look something like this:
那么为什么不用一颗石头杀死两只鸟呢?通过使用 RSpec 的共享示例组,您可以针对使用它们的实际类(例如,模型)测试您的关注点,并且您将能够在使用它们的任何地方测试它们。而且您只需编写一次测试,然后将它们包含在任何使用您关注的模型规范中。在您的情况下,这可能如下所示:
# 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
The advantages of this approach become even more obvious when you start doing things in your concern like invoking AR callbacks, where anything less than an AR object just won't do.
当你开始做你关心的事情时,这种方法的优势变得更加明显,比如调用 AR 回调,除了 AR 对象之外的任何事情都不会做。
回答by Kyle Decot
In response to the comments I've received, here's what I've ended up doing (if anyone has improvements please feel free to post them):
针对我收到的评论,以下是我最终所做的(如果有人有改进,请随时发布):
spec/concerns/personable_spec.rb
规范/关注点/personable_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
回答by lobati
Another thought is to use the with_model gemto test things like this. I was looking to test a concern myself and had seen the pg_search gem doing this. It seems a lot better than testing on individual models, since those might change, and it's nice to define the things you're going to need in your spec.
另一个想法是使用with_model gem来测试这样的事情。我想自己测试一个问题,并看到pg_search gem 这样做。这似乎比在单个模型上测试要好得多,因为它们可能会改变,并且在规范中定义您需要的东西很好。

