Ruby RSpec测试报错:如何模拟控制器实例变量的feature?方法?
解决RSpec测试中@domain为nil的问题
你遇到的undefined method 'feature?' for nil:NilClass错误,核心原因是测试时助手模块ApiHelpers所在的上下文没有初始化@domain实例变量。控制器里的@domain是在before钩子中赋值的,但测试助手模块时,这个钩子不会自动执行,所以需要手动给测试对象设置@domain。
步骤1:修正测试文件的基础错误
先把测试里的几个明显错误改过来:
- 测试的模块名应该是
ApiHelpers,不是ApiHelp - 测试的方法名要和助手方法一致:
#find_lists,不是#find_matching_lists - 不需要模拟
Domain.new,因为控制器里的@domain是从account.domain获取的,不是通过Domain.new创建的
步骤2:手动给测试对象设置@domain实例变量
在测试中,你需要给包含ApiHelpers模块的实例赋值@domain,并模拟它的feature?方法。
修正后的完整测试代码示例:
require "unit/spec_help" require_project "api/helpers/play_help.rb" RSpec.describe ApiHelpers do # 创建一个包含ApiHelpers模块的测试类,模拟控制器上下文 class TestController include ApiHelpers end describe "#find_lists" do let(:domain_double) { double("Domain") } let(:test_instance) { TestController.new } let(:sample_params) { { some_key: "value" } } let(:folders) { double("Folders") } before do # 给测试实例设置@domain变量 test_instance.instance_variable_set(:@domain, domain_double) # 模拟Domain的feature?方法返回true allow(domain_double).to receive(:feature?).with("BrandNewFeature").and_return(true) # 模拟ListQueries.folders返回预期结果 allow(ListQueries).to receive(:folders).with(sample_params).and_return(folders) end it "returns folders when BrandNewFeature is enabled" do result = test_instance.find_lists(sample_params) expect(result).to eq(folders) expect(ListQueries).to have_received(:folders).with(sample_params) end it "returns nil when BrandNewFeature is disabled" do allow(domain_double).to receive(:feature?).with("BrandNewFeature").and_return(false) result = test_instance.find_lists(sample_params) expect(result).to be_nil expect(ListQueries).not_to have_received(:folders) end end end
关键说明
- 测试类模拟上下文:创建
TestController类并包含ApiHelpers,模拟助手模块在控制器中的运行环境。 - 设置实例变量:用
instance_variable_set给测试实例手动赋值@domain,替代控制器before钩子的作用。 - 双对象模拟:用
double创建domain_double,并模拟feature?方法的返回值,覆盖不同场景(功能开启/关闭)。
这样就能解决@domain为nil的问题,同时完整测试find_lists方法的逻辑。
内容的提问来源于stack exchange,提问作者imba22
相关产品推荐
相关产品推荐

