如何在Jasmine中对依赖远程主机数据的函数进行无实际Fetch请求的测试
如何在Jasmine中对依赖远程主机数据的函数进行无实际Fetch请求的测试
我来帮你拆解这个问题,其实在Jasmine里模拟fetch请求、测试依赖远程数据的函数并不复杂,咱们一步步来解决:
一、先模拟全局fetch,避免实际发起网络请求
因为你的loadProducts依赖浏览器的全局fetch函数,所以第一步要在Jasmine里mock这个函数,让它返回咱们预设的测试数据,而不是真的去请求远程主机。
你可以用Jasmine的spyOn方法来监听全局fetch,并让它返回一个模拟的响应:
describe('Product-related functions', () => { // 在每个测试前mock fetch beforeEach(() => { // 定义模拟的远程返回数据 const mockProductData = [ { id: 1, image: 'test.jpg', name: 'Test Product', rating: { stars: 4.5 }, priceCents: 999, keywords: ['electronics'] }, { id: 2, image: 'appliance.jpg', name: 'Test Appliance', rating: { stars: 4 }, priceCents: 1999, keywords: ['appliances'] }, { id: 3, image: 'shirt.jpg', name: 'Test Shirt', rating: { stars: 3.5 }, priceCents: 499, type: 'clothing' } ]; // mock fetch,让它返回一个resolved的Promise,模拟成功响应 spyOn(window, 'fetch').and.returnValue( Promise.resolve({ json: () => Promise.resolve(mockProductData) }) ); }); });
二、测试getProduct函数
getProduct依赖全局的products数组,所以咱们可以先通过调用loadProducts(此时fetch已经被mock,会用预设数据填充products),然后测试不同场景:
it('should return the correct product when given a valid productId', async () => { // 先调用loadProducts填充products数组 await loadProducts(); const foundProduct = getProduct(2); expect(foundProduct.id).toBe(2); expect(foundProduct.name).toBe('Test Appliance'); // 还可以断言它是Appliance类的实例 expect(foundProduct instanceof Appliance).toBe(true); }); it('should return undefined when given an invalid productId', async () => { await loadProducts(); const foundProduct = getProduct(999); expect(foundProduct).toBeUndefined(); });
如果不想依赖loadProducts,也可以直接手动给products数组赋值测试数据,这样更直接:
it('should return correct product with manual test data', () => { // 手动设置products数组 products = [new Product({ id: 5, name: 'Manual Test Product' })]; const foundProduct = getProduct(5); expect(foundProduct.name).toBe('Manual Test Product'); });
三、测试loadProducts的请求和数据转换逻辑
除了测试getProduct,你还可以验证loadProducts是否正确发起请求、处理响应:
1. 验证fetch调用了正确的URL
it('should call fetch with the correct URL', async () => { const expectedUrl = 'link to host'; // 这里填你代码里实际的请求地址 await loadProducts(); expect(window.fetch).toHaveBeenCalledWith(expectedUrl); });
2. 验证返回的数据被正确转换成对应的类实例
it('should transform raw data into correct class instances', async () => { await loadProducts(); // 第一个数据是普通Product expect(products[0] instanceof Product).toBe(true); // 第二个数据包含appliances关键词,应该是Appliance实例 expect(products[1] instanceof Appliance).toBe(true); // 第三个数据type是clothing,应该是Clothing实例 expect(products[2] instanceof Clothing).toBe(true); });
3. 测试错误处理逻辑
你还可以模拟fetch失败的情况,验证错误是否被正确捕获:
it('should handle fetch errors properly', async () => { // 模拟fetch返回rejected的Promise spyOn(window, 'fetch').and.returnValue(Promise.reject(new Error('Network error'))); // 监听console.error,验证错误信息被输出 spyOn(console, 'error'); await loadProducts(); expect(console.error).toHaveBeenCalledWith('Network error'); });
小提示
- 每次测试后最好重置
products数组,避免测试之间的干扰,可以在afterEach里重置:
afterEach(() => { products = []; });
- 如果你的代码是在Node.js环境下(而非浏览器),需要mock
global.fetch而不是window.fetch。
内容来源于stack exchange
相关产品推荐
相关产品推荐

