我还没有找到一种测试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内部根源?
答案 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。