如何在ApplicationRecord抽象基类中测试方法?

时间:2016-02-12 22:54:42

标签: rspec rails-activerecord rspec-rails ruby-on-rails-5

我还没有找到一种测试ApplicationRecord方法的好方法。

假设我有一个名为one的简单方法:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  def one
    1
  end
end

我想测试一下:

describe ApplicationRecord do
  let(:it) { described_class.new }

  it 'works' do
    expect(it.one).to eq 1
  end
end

不出所料,NotImplementedError: ApplicationRecord is an abstract class and cannot be instantiated.

就死了

所以我尝试了Testing abstract classes in Rspec中的匿名班级建议:

let(:it) { Class.new(described_class).new }

这会因TypeError: no implicit conversion of nil into String而死,大概是因为记录的表名是零。

有人能建议一种测试ApplicationRecord方法的简单方法吗?希望不会在我的应用程序中引入其他类的依赖关系,而不是在ActiveRecord内部根源?

3 个答案:

答案 0 :(得分:5)

我建议将这些方法提取到模块(关注点)并单独留下ApplicationRecord。

module SomeCommonModelMethods
  extend ActiveSupport::Concern

  def one
    1
  end
end

class ApplicationRecord < ActiveRecord::Base
  include SomeCommonModelMethods
  self.abstract_class = true
end

describe SomeCommonModelMethods do
  let(:it) { Class.new { include SomeCommonModelMethods }.new } } 

  it 'works' do
    expect(it.one).to eq 1
  end
end

答案 1 :(得分:4)

这在我们的测试中一直在为我工作:

class TestClass < ApplicationRecord
  def self.load_schema!
    @columns_hash = {}
  end
end

describe ApplicationRecord do
  let(:record) { TestClass.new }

  describe "#saved_new_record?" do
    subject { record.saved_new_record? }

    before { allow(record).to receive(:saved_change_to_id?).and_return(id_changed) }

    context "saved_change_to_id? = true" do
      let(:id_changed) { true }

      it { is_expected.to be true }
    end

    context "saved_change_to_id? = false" do
      let(:id_changed) { false }

      it { is_expected.to be false }
    end
  end
end

它只是阻止类尝试数据库连接来加载表模式。

显然,随着Rails的移动,你可能不得不更新你的方式,但至少它位于一个容易找到的地方。

我更喜欢这个,而不仅仅是让另一个模块允许测试。

答案 2 :(得分:1)

如果您正在使用Rspec,那么您可以创建一个shared example,然后从继承自ApplicationRecord的每个模型的规范中调用它。这样做的缺点是在每个模型上测试所有这些行为,但是开销应该相当低,除非你把很多共享行为塞进ApplicationRecord。