如何测试 ApplicationRecord 抽象基 class 中的方法?

How can I test methods in the ApplicationRecord abstract base class?

我还没有找到测试 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.

所以我尝试了 中的匿名 class 建议:

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

这与 TypeError: no implicit conversion of nil into String 一起消失,大概是因为记录的 table 名称为 nil。

任何人都可以建议一种测试 ApplicationRecord 方法的简单好方法吗?希望它不会在我的应用程序中引入对其他 class 的依赖性并且不会在 ActiveRecord 内部产生影响?

我建议将这些方法提取到模块(关注)中,并单独保留 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

这在我们的测试中对我有用:

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

它只是阻止 class 尝试通过数据库连接加载 table 模式。

显然,随着 Rails 的发展,您可能需要更新执行此操作的方式,但至少它位于一个容易找到的地方。

我更喜欢这个,而不是仅仅为了测试而使用另一个模块。

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