You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RSpec控制器GET #index测试返回空ActiveRecord::Relation数组而非预期模型实例求助

问题分析与解决方案

看起来你遇到的问题核心是测试数据的创建时机和RSpec的事务隔离机制冲突,导致控制器查询不到你提前创建的Script记录。

为什么会失败?

你把userID_1和script1的创建代码放在了describe ScriptsController块的顶层——这部分代码会在RSpec加载测试文件时就执行,但RSpec的控制器测试默认会为每个it块启动一个独立的数据库事务,测试结束后自动回滚。这就导致你在顶层创建的记录,并不在当前测试例子的事务范围内,所以控制器执行Script.order(:created_at)时,查询不到这些记录,返回了空的ActiveRecord::Relation。

而你看到p script1能输出记录,是因为这个记录确实在数据库里存在,但它不在当前测试的事务中,控制器的查询无法访问到。


修复方案

方案1:调整测试数据的创建时机(快速修复)

把数据创建移到测试块内的before钩子或者用let!(注意是带感叹号的let!,它会提前加载数据,而不是懒加载),确保数据在当前测试事务内创建:

require 'rails_helper'
describe ScriptsController, type: :controller do
  describe "GET #index" do
    # 用let!确保数据在请求发送前就创建完成
    let!(:user) { User.create!(
      email: 'ueferfrfrf@u1.com',
      password: 'useruser',
      password_confirmation: 'useruser'
    ) }
    let!(:script1) { Script.create!(
      name: 'YWoodcutter',
      skill: 'Woodcutting',
      bot_for: 'TRiBot',
      game_for: 'Oldschool Runescape 07',
      user_id: user.id
    ) }

    it "assigns @scripts" do
      get :index
      expect(assigns(:scripts)).to eq([script1])
    end
  end
end

方案2:改用FactoryBot创建测试数据(更规范)

既然你已经引入了FactoryBot,推荐用它定义工厂,让测试代码更简洁易维护,还能避免重复代码:

首先定义工厂文件:

# spec/factories/users.rb
FactoryBot.define do
  factory :user do
    email { Faker::Internet.unique.email }
    password { 'useruser' }
    password_confirmation { 'useruser' }
  end
end

# spec/factories/scripts.rb
FactoryBot.define do
  factory :script do
    name { 'YWoodcutter' }
    skill { 'Woodcutting' }
    bot_for { 'TRiBot' }
    game_for { 'Oldschool Runescape 07' }
    association :user # 自动关联一个User实例,无需手动创建
  end
end

然后修改测试代码:

require 'rails_helper'
describe ScriptsController, type: :controller do
  describe "GET #index" do
    let!(:script1) { create(:script) }

    it "assigns @scripts ordered by created_at" do
      get :index
      # 用match_array可以忽略顺序(如果需要严格验证顺序,依然用eq即可)
      expect(assigns(:scripts)).to match_array([script1])
    end
  end
end

额外提示

  • 避免在describe块顶层创建测试数据,这会污染测试数据库(因为不在测试事务中,不会被回滚),还会导致测试之间的依赖问题。
  • RSpec Rails默认的数据库清理策略是:transaction,这个策略对控制器测试非常友好,能保证每个测试的独立性,不用手动清理数据。

内容的提问来源于stack exchange,提问作者AakLak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 20:42:35