gpt4 book ai didi

ruby-on-rails - 在不加载模型的情况下引用 Rails 模型的单元测试代码

转载 作者:太空宇宙 更新时间:2023-11-03 16:40:41 26 4
gpt4 key购买 nike

我正在尝试对一个普通的旧 Ruby 对象进行单元测试,该对象具有调用 Rails 模型上的类方法的方法。 Rails 应用程序非常大(加载需要 10 秒),所以我宁愿避免加载所有 Rails 来进行我的单元测试,它应该在 1 秒内运行。

例子:

class Foo
def bar
SomeRailsModel.quxo(3)
end
end

RSpec.describe Foo do
let(:instance) { Foo.new }

it 'calls quxo on SomeRailsModel' do
expect(SomeRailsModel).to receive(:quxo)
instance.bar
end
end

这里的问题是我需要require 'rails_helper' 加载Rails 以便app/models/some_rails_model 可用。由于依赖 Rails,这会导致单元测试缓慢。

我试过在本地定义常量,然后使用常规 spec_helper 哪种方法有效。

例子:

RSpec.describe Foo do
let(:instance) { Foo.new }
SomeRailsModel = Object.new unless Kernel.const_defined?(:SomeRailsModel)

it 'calls quxo on SomeRailsModel' do
expect(SomeRailsModel).to receive(:quxo)
instance.bar
end
end

此代码让我避免加载所有 Rails 并且执行速度非常快。不幸的是,默认情况下(我喜欢这样)RSpec 将常量视为部分 double 常量并提示我的 SomeRailsModel 常量不响应 quxo 消息。验证 double 很好,我想保持安全带。我可以通过将验证包装在 RSpec 定义的特殊 block 中来单独禁用验证。

最后是问题。在不需要所有 Rails 的情况下对使用 Rails 模型的 PORO 进行快速单元测试的推荐方法是什么,同时还保持启用验证 double 功能?有没有一种方法可以创建一个“ slim 的”rails_helper,它可以只加载 app/modelsActiveRecord 的最小子集来进行验证?

最佳答案

在和同事们商量了一些想法后,这里是共识解决方案:

class Foo
def bar
SomeRailsModel.quxo(3)
end
end

require 'spec_helper' # all we need!

RSpec.describe Foo do
let(:instance) { Foo.new }
let(:stubbed_model) do
unless Kernel.const_defined?("::SomeRailsModel")
Class.new { def self.quxo(*); end }
else
SomeRailsModel
end
end

before { stub_const("SomeRailsModel", stubbed_model) }

it 'calls quxo on SomeRailsModel' do
expect(stubbed_model).to receive(:quxo)
instance.bar
end
end

在本地运行时,我们将检查模型类是否已经定义。如果有,使用它 因为我们已经为加载该文件付出了代价。如果不是,则创建一个实现被测接口(interface)的匿名类。使用 stub_const 在匿名类或真实交易中 stub 。

对于本地测试,这会非常快。对于在 CI 服务器上运行的测试,我们会检测到模型已经加载并优先使用它。在所有情况下,我们也会获得自动双重方法验证。

如果真实的 Rails 模型接口(interface)发生变化但匿名类落后,CI 运行将捕获它(或者集成测试将捕获它)。

更新:我们可能会使用 spec_helper.rb 中的辅助方法稍微干一下。如:

def model_const_stub(name, &blk)
klass = unless Kernel.const_defined?('::' + name.to_s)
Class.new(&blk)
else
Kernel.const_get(name.to_s)
end

stub_const(name.to_s, klass)
klass
end

# DRYer!
let(:model) do
model_const_stub('SomeRailsModel') do
def self.quxo(*); end
end
end

可能不是最终版本,但这给出了我们的方向。

关于ruby-on-rails - 在不加载模型的情况下引用 Rails 模型的单元测试代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54373597/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com