在单元测试中反应反应值

React reactive values in unit tests

提问人:Daniel 提问时间:11/1/2023 更新时间:11/1/2023 访问量:22

问:

我正在尝试使用“React 上下文依赖注入”对 react 钩子进行单元测试,以便能够更好地应用测试驱动开发(在阅读了两篇关于它的帖子后 https://blog.testdouble.com/posts/2021-03-19-react-context-for-dependency-injection-not-state/https://medium.com/@matthill8286/dependency-injection-in-react-a-good-guide-with-code-examples-4afc8adc6cdb)。

现在我想伪造/模拟一个钩子的反应性返回值,以便测试另一个钩子并验证它是否对其依赖项的变化做出反应。我准备了一个堆栈闪电战示例:https://stackblitz.com/edit/vitejs-vite-nwro2m?file=src%2FUseUsername.ts

// DependencyContext.ts

import { createContext } from 'react';

export interface Dependencies {
  useUserId: () => string;
}

export const DependencyContext = createContext<Dependencies>(null!);

我要测试的钩子是用工厂创建的,以便注入一些预配置的函数,该函数将用户名返回给给定的 userId。它还使用从 DependencyContext 返回。useUserId

// UseUsername.ts

import { useContext } from 'react';
import { DependencyContext } from './DependencyContext';

export function createUseUsername(userNameApi: (userId: string) => string) {
  return function () {
    const { useUserId } = useContext(DependencyContext);
    const userId = useUserId();
    return userNameApi(userId);
  };
}

使用工厂和 DependencyContext 可以包含测试,隔离钩子,并且不需要模拟模块。 在下面的测试中,我想验证钩子在 userId 更改时是否更新其值。

// UseUsername.test.tsx

import { describe, test, expect } from 'vitest';
import { renderHook, act } from '@testing-library/react';
import { createUseUsername } from './UseUsername';
import { DependencyContext } from './DependencyContext';
describe('UseUsername', () => {
  test('it returns correct name for a given userId', () => {
    function usernameApiFake(userId: string): string {
      const users: Record<string, string> = {
        userA: 'usernameA',
        userB: 'usernameB',
      };
      return users[userId] ?? '';
    }

    let userId = 'userA';
    const useUserIdFake = () => userId;

    const { result, rerender } = renderHook(
      createUseUsername(usernameApiFake),
      {
        wrapper: ({ children }) => (
          <DependencyContext.Provider value={{ useUserId: useUserIdFake }}>
            {children}
          </DependencyContext.Provider>
        ),
      }
    );

    expect(result.current).toBe('usernameA');

    act(() => (userId = 'userB'));
    rerender(); // I don't want to have to call a rerender

    expect(result.current).toBe('usernameB');
  });
});

问题是钩子不会更新,如果我更改.我必须显式地重新渲染钩子。 我的问题:userId

  • 有没有办法使反应式,以便在更改时渲染的钩子自动重新渲染?userIduserId
  • 还是显式调用等效且足以对这个钩子进行单元测试?rerender
reactjs 单元 react-hooks tdd 反应测试库

评论


答: 暂无答案