You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为ApolloClient的缓存更新逻辑编写单元测试?

测试useMutation中update方法的缓存更新逻辑

依赖准备

确保测试环境已安装以下依赖:

  • @apollo/client/testing:提供MockedProvider和缓存操作工具
  • @testing-library/react:用于渲染Hook、触发异步操作
  • @testing-library/jest-dom:用于断言缓存数据

完整测试代码示例

import { renderHook, act } from '@testing-library/react';
import { MockedProvider, InMemoryCache } from '@apollo/client/testing';
import { useMutation } from '@apollo/client';
import updateRecordMutation from './path-to-your-mutation-file';
import GetRecord from './path-to-your-get-record-query';

// 测试用初始缓存数据
const initialCacheData = {
  Record: {
    __typename: 'Record',
    recordId: '123',
    recordName: '旧名称'
  }
};

// Mutation的模拟返回结果
const mockMutationResult = {
  data: {
    updateRecord: {
      __typename: 'UpdateRecordResponse',
      recordName: '新名称'
    }
  }
};

describe('useMutation的update缓存更新逻辑', () => {
  it('能正确更新缓存中的recordName字段', async () => {
    // 初始化缓存并写入初始数据
    const cache = new InMemoryCache();
    cache.writeQuery({
      query: GetRecord,
      variables: { recordId: '123' },
      data: initialCacheData
    });

    // 渲染Hook并包裹MockedProvider
    const { result } = renderHook(() => useMutation(updateRecordMutation), {
      wrapper: ({ children }) => (
        <MockedProvider
          mocks={[
            {
              request: {
                query: updateRecordMutation,
                variables: { recordId: '123', recordName: '新名称' }
              },
              result: mockMutationResult
            }
          ]}
          cache={cache}
        >
          {children}
        </MockedProvider>
      )
    });

    const [updateRecord] = result.current;

    // 触发Mutation调用(用act包裹确保状态更新完成)
    await act(async () => {
      await updateRecord({
        variables: { recordId: '123', recordName: '新名称' },
        // 直接复用组件中的update逻辑,避免重复编写
        update(cache, result) {
          const updatedData = result.data?.updateRecord?.recordName;
          const cachedData = cache.readQuery({
            query: GetRecord,
            variables: { recordId: '123' },
          });
          if (cachedData?.Record) {
            cachedData.Record.recordName = updatedData;
            cache.writeQuery({
              query: GetRecord,
              variables: { recordId: '123' },
              data: cachedData,
            });
          }
        }
      });
    });

    // 读取缓存并验证更新结果
    const updatedCacheData = cache.readQuery({
      query: GetRecord,
      variables: { recordId: '123' }
    });

    expect(updatedCacheData?.Record.recordName).toBe('新名称');
  });
});

关键注意事项

  • 必须预加载初始缓存:如果不提前写入初始数据,update方法中cache.readQuery会返回undefined,直接跳过更新逻辑。
  • 严格匹配请求参数:MockedProvider中配置的request的variables,必须和调用updateRecord时的variables完全一致,否则Mutation不会触发模拟返回,update方法也不会执行。
  • 用act包裹异步操作:确保Mutation和缓存更新的异步逻辑全部完成后再做断言,避免测试不稳定。
  • 复用业务逻辑:把组件中的update逻辑抽成独立函数,测试时直接调用该函数,保证测试逻辑和业务逻辑完全一致,减少维护成本。

缓存未更新的常见排查点

  • 初始缓存未正确写入,导致cachedData为undefined
  • Mutation的模拟返回结构和实际不一致,比如缺少updateRecord字段,导致updatedData为undefined
  • 请求参数和Mock配置不匹配,Mutation未触发模拟返回
  • 写入缓存时的query、variables和读取时不一致,导致无法读取到更新后的数据

内容的提问来源于stack exchange,提问作者athi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:22:28