如何在Rails中用RSpec测试DB返回的特定对象是否被调用指定方法
正确测试方案
你遇到的报错有三个核心原因:
- 拼写错误:RSpec的匹配器是
have_received,你写成了have_recieved - 你没有给测试创建的u1、u2实例开启消息调用跟踪,仅用
allow_any_instance_of不会自动为具体实例记录调用情况 - 原
UserDanger类中定义的perform_dangerous_action是实例方法,你测试中直接调用类方法UserDanger.perform_dangerous_action也会触发错误
方案1:针对具体实例监听调用(最直观)
直接给你创建的两个测试用户实例设置mock,跟踪它们的方法调用:
it "executes dangerous_action only for non-Fred users" do # 先创建测试数据 u1 = FactoryBot.create(:user, name: "Jill") u2 = FactoryBot.create(:user, name: "Fred") # 给两个实例单独设置方法mock,同时开启调用记录 allow(u1).to receive(:dangerous_action) allow(u2).to receive(:dangerous_action) # 注意这里是先实例化再调用,不是直接调类方法 UserDanger.new.perform_dangerous_action # 断言调用情况 expect(u1).to have_received(:dangerous_action) expect(u2).not_to have_received(:dangerous_action) end
方案2:全局计数校验(适合批量操作场景)
如果需要校验批量调用的数量和匹配规则,可以用块形式的全局mock来实现:
it "triggers dangerous_action for all non-Fred users" do # 创建多组测试数据验证规则 FactoryBot.create(:user, name: "Jill") FactoryBot.create(:user, name: "Fred") FactoryBot.create(:user, name: "Bob") valid_call_count = 0 allow_any_instance_of(User).to receive(:dangerous_action) do |user| # 校验所有被调用的用户都不是Fred expect(user.name).not_to eq("Fred") valid_call_count += 1 end UserDanger.new.perform_dangerous_action # 校验总调用次数符合预期(排除了1个Fred) expect(valid_call_count).to eq(2) end
注意事项
不要为了方便直接mockUser.where方法,这样会跳过ActiveRecord的实际查询逻辑,如果你把where.not(name: "Fred")写错成where(name: "Fred"),mock查询的测试会发现不了这个逻辑错误。
内容的提问来源于stack exchange,提问作者Toby 1 Kenobi
相关产品推荐
相关产品推荐

