Worker与Controller测试疑难:任务计数为0及Mock困惑
问题解决指南
一、Worker测试计数为0的原因及修复
你当前的Worker测试直接调用了worker.perform(username, email),这是同步执行任务,不会将任务添加到jobs队列中——只有调用perform_async(或perform_in这类异步方法)才会把任务存入队列。
修复后的Worker测试代码
describe HistoryWorker do let(:username) { "test_user" } let(:email) { "test@example.com" } it "成功执行HistoryEvent服务逻辑" do # 验证HistoryEvent的event方法被正确调用 expect_any_instance_of(HistoryEvent).to receive(:event) described_class.new.perform(username, email) end # 若要测试异步入队逻辑,改用perform_async it "将任务加入队列" do described_class.perform_async(username, email) expect(described_class.jobs.count).to eq(1) end end
二、控制器测试的正确姿势
控制器测试的核心是触发create动作,再验证update_history方法是否正确调用了Worker的异步方法。另外要确保测试环境中,异步任务不会被立即执行,而是存入内存队列(以Sidekiq为例,需配置测试模式)。
步骤1:配置测试环境的Worker队列(以Sidekiq为例)
在spec_helper.rb或rails_helper.rb中添加:
require 'sidekiq/testing' Sidekiq::Testing.fake! # 让任务存入内存队列,不实际执行
步骤2:修复控制器测试代码
describe YourController do describe "#create" do it "触发update_history并添加HistoryWorker任务" do # 先触发create动作,传入符合你业务的参数 post :create, params: { your_model: { name: "test", ... } } # 验证Worker任务是否入队 expect(HistoryWorker.jobs.count).to eq(1) # 额外验证入队参数是否正确 expect(HistoryWorker.jobs.first["args"]).to eq(["expected_username", "expected_email"]) end end end
关于Mock的选择
如果你不想依赖队列配置,也可以直接MockHistoryWorker.perform_async,直接验证方法调用逻辑:
describe YourController do describe "#create" do it "调用HistoryWorker.perform_async" do expect(HistoryWorker).to receive(:perform_async).with("expected_username", "expected_email") post :create, params: { your_model: { ... } } end end end
额外注意点
你的Worker代码存在参数错误:perform方法接收的是username和email,但调用HistoryEvent.new(params)时用了未定义的params,应该改成HistoryEvent.new(username: username, email: email).event,或者把参数组装成符合服务要求的哈希传入。
内容的提问来源于stack exchange,提问作者Kumar Nikhil
相关产品推荐
相关产品推荐

