MST

星途 面试题库

面试题:React Hooks测试中模拟异步操作

假设你有一个使用了useEffect Hook的组件,在这个Hook中发起了一个异步的API调用,并将结果存储在useState中。请说明如何使用测试工具对这一异步操作进行模拟和测试,以确保数据获取和状态更新逻辑正确。
14.6万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试
  1. 选择测试工具

    • 对于React组件测试,通常会使用@testing - library/reactjest@testing - library/react专注于测试React组件的用户界面行为,而jest是一个功能强大的JavaScript测试框架,提供了模拟函数、定时器等功能,方便处理异步操作。
  2. 安装依赖

    npm install --save - dev @testing - library/react jest
    
  3. 编写测试用例

    • 假设组件如下:
    import React, { useState, useEffect } from'react';
    
    const MyComponent = () => {
      const [data, setData] = useState(null);
    
      useEffect(() => {
        const fetchData = async () => {
          const response = await fetch('https://example.com/api/data');
          const result = await response.json();
          setData(result);
        };
        fetchData();
      }, []);
    
      return <div>{data? JSON.stringify(data) : 'Loading...'}</div>;
    };
    
    export default MyComponent;
    
    • 测试用例如下:
    import React from'react';
    import { render, screen } from '@testing - library/react';
    import MyComponent from './MyComponent';
    
    jest.mock('react - native/Libraries/Network/XMLHttpRequest', () => {
      const XMLHttpRequest = jest.requireActual('react - native/Libraries/Network/XMLHttpRequest');
      return {
       ...XMLHttpRequest,
        open: jest.fn(),
        send: jest.fn(),
        setRequestHeader: jest.fn(),
        addEventListener: jest.fn(),
        onreadystatechange: jest.fn()
      };
    });
    
    global.fetch = jest.fn(() =>
      Promise.resolve({
        json: () => Promise.resolve({ key: 'value' })
      })
    );
    
    test('MyComponent fetches data and updates state', async () => {
      render(<MyComponent />);
      await screen.findByText('{"key":"value"}');
    });
    
    • 解释
      • 首先使用jest.mock模拟XMLHttpRequest相关方法(在浏览器环境下测试React组件时,fetch基于XMLHttpRequest),以确保测试环境的一致性。
      • 使用global.fetch = jest.fn()模拟fetch函数,使其返回一个已解析的Promise,模拟API成功响应的情况。这里返回的数据结构{ key: 'value' }应根据实际API返回结构调整。
      • 在测试用例中,使用render渲染组件,然后使用await screen.findByText等待组件渲染出包含API返回数据的文本。findByText会在组件渲染后持续查找文本,直到找到或超时,这样能确保异步操作完成后才断言测试结果。
  4. 处理错误情况

    • 要测试API调用失败的情况,可以修改fetch模拟函数,使其返回一个被拒绝的Promise:
    global.fetch = jest.fn(() =>
      Promise.reject(new Error('Network error'))
    );
    
    test('MyComponent handles fetch error', async () => {
      render(<MyComponent />);
      try {
        await screen.findByText('Loading...');
        expect(screen.queryByText('Network error')).toBeNull();
      } catch (error) {
        expect(error.message).toContain('Network error');
      }
    });
    
    • 解释
      • 这里模拟fetch函数返回一个被拒绝的Promise,抛出Network error错误。
      • 在测试用例中,使用try - catch块捕获错误。首先期望能找到Loading...文本,因为数据加载失败时组件应显示加载状态。然后使用screen.queryByText查找错误信息文本,期望它为null,表示组件没有显示错误信息(实际处理可能会根据业务需求调整,如显示错误提示)。如果捕获到错误,断言错误信息包含Network error,以确保错误处理逻辑正确。