Jasmine测试:如何验证作为参数传入的回调方法被正确执行
问题原因
- 异步逻辑未等待就执行断言:
axios.get返回的是Promise,其then回调属于微任务,会等待当前所有同步代码(也就是你写的expect断言)执行完毕后才会运行。你执行断言时onSuccess回调根本还没有被触发,所以测试失败,而控制台后续打印出foo是因为测试跑完之后微任务才正式执行。 - 验证方式冗余:不需要绕到
console.log间接验证回调触发,直接给onSuccess本身创建spy更直观,也能避免函数调用上下文带来的监听偏差。
修复后的测试代码
推荐用Jasmine的async/await方案处理异步测试,代码更简洁:
// agency_controller.spec.js import { getProducerNamesAndBillingPlan } from "../../../../app/javascript/packs/controllers/agencies_controller"; import axios from 'axios'; const mockAxiosPromise = (response) => { return Promise.resolve({ status: 200, data: response}); } describe('#getProducerNamesAndBillingPlan', () => { it('calls the given onSuccess method if the request is successful', async () => { // 直接mock axios.get返回结果 spyOn(axios, 'get').and.returnValue(mockAxiosPromise('foo')); // 给onSuccess创建专用spy,监听调用情况 const mockOnSuccess = jasmine.createSpy('mockOnSuccess'); getProducerNamesAndBillingPlan({ agencyId: 1, onSuccess: mockOnSuccess }); // 等待所有已入队的微任务(包括axios的then回调)执行完成 await Promise.resolve(); // 直接断言回调被调用且参数正确 expect(mockOnSuccess).toHaveBeenCalledOnceWith('foo'); }); })
也可以用Jasmine的done回调方案实现相同效果:
it('calls the given onSuccess method if the request is successful', (done) => { spyOn(axios, 'get').and.returnValue(mockAxiosPromise('foo')); const mockOnSuccess = jasmine.createSpy('mockOnSuccess').and.callFake(() => { expect(mockOnSuccess).toHaveBeenCalledOnceWith('foo'); // 回调执行后调用done,告知Jasmine异步测试完成 done(); }); getProducerNamesAndBillingPlan({ agencyId: 1, onSuccess: mockOnSuccess }); })
内容的提问来源于stack exchange,提问作者N. Cashman
相关产品推荐
相关产品推荐

