如何测试Rails中的关注点

Kyl*_*cot 97 testing rspec ruby-on-rails

鉴于我Personable在我的Rails 4应用程序中有一个问题有一个full_name方法,我将如何使用RSpec进行测试?

关注/ personable.rb

module Personable
  extend ActiveSupport::Concern

  def full_name
    "#{first_name} #{last_name}"
  end
end
Run Code Online (Sandbox Code Playgroud)

Jos*_*zel 164

你找到的方法肯定会测试一些功能,但看起来很脆弱 - 你的虚拟类(实际上只是Struct你的解决方案中)可能会或可能不会像include你关注的真正的类一样.此外,如果您尝试测试模型问题,除非您相应地设置数据库,否则您将无法测试对象的有效性或调用ActiveRecord回调(因为您的虚拟类将没有数据库表支持)它).此外,您不仅要测试关注点,还要测试模型规范中关注点的行为.

那么为什么不一石二鸟呢?通过使用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
Run Code Online (Sandbox Code Playgroud)

当您开始处理关注事项时,这种方法的优势变得更加明显,例如调用AR回调,其中任何比AR对象更少的东西都不会.

  • 确保在`spec_helper.rb`中包含`concerns`目录.https://github.com/rspec/rspec-core/issues/407#issuecomment-1409871 (8认同)
  • @ArtemKalinchuk我不确定这是真的,根据https://github.com/grosser/parallel_tests/issues/168`andder_tests`基于每个文件,因此共享示例不应该减慢速度.我还认为正确分组共享行为,胜过测试速度. (5认同)
  • 不要将`_spec`添加到包含shared_examples_for(在本例中为personable_spec.rb)的文件名中,否则您将收到误导性警告消息 - https://github.com/rspec/rspec-core/issues/828. (3认同)
  • 这样做的一个缺点是它会减慢`parallel_tests`的速度.我认为使用单独的测试而不是使用`shared_examples_for`和`it_behaves_like`会更好. (2认同)
  • 我找不到任何关于在该链接中包含关注目录的信息。你能澄清一下这是如何完成的吗?我无法通过 RSpec 测试来识别我关注的模块之一。 (2认同)

Kyl*_*cot 56

回应我收到的评论,这是我最终做的事情(如果有人有改进,请随时发布):

规格/关注/ 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
Run Code Online (Sandbox Code Playgroud)

  • 是的,如果他们碰巧测试一个名为“Person”的真实类,这将破坏其他测试。我会编辑修复。 (2认同)

lob*_*ati 6

另一个想法是使用with_model gem测试这种事情。我当时想亲自测试一个问题,并且看到了pg_search宝石正在这样做。这似乎比对单个模型进行测试要好得多,因为它们可能会发生变化,并且很好地定义规范中需要的东西。