如何用Minitest测试外部API轮询?Mock/Stub请求失败求助
解决Mocha Mock/Stub BaseApi 相关调用的问题
看起来你在测试Sidekiq Worker时,Mock BaseApi.authenticate 和 BaseApi::TrackableJob 这两个API调用遇到了问题。结合你提供的代码和Mocha的特性,我来帮你梳理下正确的Mock方式:
核心问题分析
你的代码里有两个关键依赖需要Mock:
BaseApi.authenticate(1)是一个带块的方法,必须让它执行块内的逻辑,否则后续的TrackableJob调用不会触发;BaseApi::TrackableJob.find(job_id).first是链式调用,需要分步Mock才能覆盖到.first的返回值。
具体测试用例示例
下面是针对不同Job状态的测试代码,你可以直接参考:
describe BaseApis::PollTrackableJobWorker do let(:job_id) { 'test-job-uuid' } let(:dummy_invoice_id) { 'dummy-invoice-123' } # 测试状态为'done'的场景 it 'returns true when the job completes successfully' do # Mock BaseApi.authenticate,指定参数并让它执行块内代码 BaseApi.expects(:authenticate).with(1).yields # 链式Mock TrackableJob.find -> first trackable_job_mock = mock('TrackableJobResponse') trackable_job_mock.expects(:first).returns({ 'status' => 'done' }) BaseApi::TrackableJob.expects(:find).with(job_id).returns(trackable_job_mock) worker = BaseApis::PollTrackableJobWorker.new result = worker.perform(job_id, dummy_invoice_id) expect(result).to be(true) end # 测试状态为'error'的场景 it 'triggers Bugsnag notification when job fails' do error_details = { 'status' => 'error', 'errors' => 'Failed to process document' } BaseApi.expects(:authenticate).with(1).yields trackable_job_mock = mock('TrackableJobResponse') trackable_job_mock.expects(:first).returns(error_details) BaseApi::TrackableJob.expects(:find).with(job_id).returns(trackable_job_mock) # 验证Bugsnag.notify被正确调用 Bugsnag.expects(:notify).with('Failed to process document') worker = BaseApis::PollTrackableJobWorker.new worker.perform(job_id, dummy_invoice_id) end # 测试状态为'pending'或'running'的场景 it 'raises EDocumentNotSentError for pending/running jobs' do ['pending', 'running'].each do |status| BaseApi.expects(:authenticate).with(1).yields trackable_job_mock = mock('TrackableJobResponse') trackable_job_mock.expects(:first).returns({ 'status' => status }) BaseApi::TrackableJob.expects(:find).with(job_id).returns(trackable_job_mock) worker = BaseApis::PollTrackableJobWorker.new expect { worker.perform(job_id, dummy_invoice_id) }.to raise_error(EDocumentNotSentError) end end end
关键注意事项
- 必须给
authenticate加.yields:如果忘记这个,块内的代码不会执行,你Mock的TrackableJob调用永远不会触发,看起来就像Mock失败了; - 链式调用要分步Mock:不能直接写
BaseApi::TrackableJob.expects(:find).with(job_id).first.returns(...),得先让find返回一个mock对象,再给这个对象的first方法设置返回值; - 参数匹配要准确:确保
authenticate的参数1和find的job_id都和代码里的调用完全匹配,否则Mocha会认为调用不匹配,Mock不生效。
内容的提问来源于stack exchange,提问作者ogirginc
相关产品推荐
相关产品推荐

