如何在Rails中测试问题


104

考虑到Personable我的Rails 4应用程序中有一个full_name方法,我应该如何使用RSpec对此进行测试?

关注/personable.rb

module Personable
  extend ActiveSupport::Concern

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

您正在使用什么测试框架?还要记住,Personable只是一个普通的Ruby模块。像测试其他任何mixin一样对其进行测试。
李·贾维斯

ActiveSupport::Concern被带出Rails吗?我以为它是前一阵子。
罗素

@LeeJarvis我正在使用带有工厂女孩的Rspec
Kyle Decot


4
@罗素,我同意。就是说,我不会仅仅因为他们正在遵循Rails-y的方式来做我不同意的事情,就不会帮助他们。无论如何,这有点逃避了这个问题的主题:-)
Lee Jarvis,

Answers:


176

您找到的方法肯定可以测试一点功能,但看起来很脆弱-您的虚拟类(实际上只是Struct您的解决方案中的a)可能会或可能不会像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

当您开始处理自己关心的事情(如调用AR回调)时,这种方法的优势就变得更加明显,而AR对象之外的任何事情都将无法实现。


2
这样的缺点之一是它会减慢速度 parallel_tests。我认为最好有单独的测试,而不要使用shared_examples_forit_behaves_like
Artem Kalinchuk 2014年

5
@ArtemKalinchuk我不确定是真的,每个github.com/grosser/parallel_tests/issues/168 parallel_tests是基于每个文件的,因此共享示例不应减慢它的速度。我还认为,正确分组的共享行为会降低测试速度。
亚伦K

8
确保concerns在您的目录中包含目录spec_helper.rb github.com/rspec/rspec-core/issues/407#issuecomment-1409871
Ziggy

1
我在该链接中找不到有关关注目录的任何信息。您能说明一下如何完成吗?我无法通过RSpec测试来识别模块,这是我关注的问题之一。
杰克·史密斯 Jake Smith)

4
不要添加_spec到包含shared_examples_for(在这种情况下为personable_spec.rb)的文件名中,否则您将收到一个误导性的警告消息-github.com/rspec/rspec-core/issues/828
拉鲁

62

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

规范/问题/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

1
是的,如果碰巧测试了称为的真实类,这将破坏其他测试Person。我将进行修复。
罗素

这行不通。它给了我错误:undefined method 'full_name' for #<struct first_name="Stewart", last_name="Home">
Kyle Decot

尝试包括Personable而不是扩展它。我将更新答案。
罗素

现在效果很好。感谢您为我指出正确的方向并帮助我重构@Russell
Kyle Decot

效果很好,看起来很好
Edward

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.