如何在要测试的 React 组件中模拟自定义钩子? [英] How to mock a custom hook inside of a React component you want to test?

查看:44
本文介绍了如何在要测试的 React 组件中模拟自定义钩子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果您有一个 React 组件调用一个获取数据的自定义钩子,那么在测试 React 组件时模拟该内部自定义钩子结果的最佳方法是什么?我看到两种主要方法:

If you have a React component that calls a custom hook that fetches data, what is the best way to mock that internal custom hook result when testing the React component? I see 2 main approaches:

1) Jest.mock 自定义钩子.这似乎是最推荐的方法,但它似乎需要测试对内部实现细节以及它可能需要模拟的内容有更多的了解,而不是组件的 props 接口可能建议的内容(假设使用 prop-types 或打字稿)

1) Jest.mock the custom hook. This seems to be the most recommended approach, but it seems like it requires the test to have more knowledge of internal implementation details and what it might need to mock than what the props interface of the component might suggest (assuming use of prop-types or TypeScript)

2) 使用依赖注入方法.将钩子声明为道具,但默认为真正的钩子,因此您不必在渲染组件的任何地方设置它,但允许使用模拟进行测试.这是一个人为的代码和框示例,其中包含一个模拟自定义钩子的测试:

2) Use a dependency injection approach. Declare the hook as a prop, but default it to the real hook so you don't have to set it everywhere you render the component, but allow overriding with a mock for tests. Here is a contrived codesandbox example with a test that mocks a custom hook:

https://codesandbox.io/s/dependency-inject-custom-hook-for-testing-mjqlf?fontsize=14&module=%2Fsrc%2FApp.js

2 需要更多的输入,但似乎更容易用于测试.但是,测试已经必须了解组件的内部实现细节才能测试渲染输出的任何条件逻辑,所以这可能并不重要,而 1 是最好的方法.1是要走的路吗?你看到了什么权衡?我是否完全错过了另一种方法?

2 requires more typing, but seems easier to work with for testing. However, tests already have to have knowledge of internal implementation details of component to test any conditional logic for rendered output, so maybe that's not important and 1 is the best approach. Is 1 the way to go? What tradeoffs do you see? Am I missing another approach altogether?

推荐答案

这个问题已经有几个月了,但如果你还没有找到好的解决方案,我写了一个可能有帮助的包.我经历了类似的思考过程,包括如果我将钩子注入到组件中会怎样?"事情变得很奇怪.

This question is a few months old, but if you haven't found a good solution, I wrote a package that might help. I went through a similar thought process, including "what if I inject the hooks into the component?" Things got weird.

我基本上想要一个连接器来避免为展示组件使用额外的包装器来测试它们.

I basically wanted a connecter to avoid an extra wrapper for presentational components just to test them.

我提出了 react-hooks-compose,它可以让您将钩子和演示者分开,并单独或一起测试它们:https://www.npmjs.com/package/react-hooks-compose

I came up with react-hooks-compose, which lets you keep your hooks and your presenters separate, and test them individually or together: https://www.npmjs.com/package/react-hooks-compose

export const useFetch = () => {
  const [user, setUser] = useState();

  useEffect(() => {
    fetchData('some-url') // <-- Fetches data on mount
      .then(res => setUser(res.data));
  }, []);

  return {user};
}

// composeHooks passes the values from your hooks as props
export const UserPresenter = ({user}) => {
  return <div>You fetched data for: {user.name}</div>;
}

export default composeHooks({ useFetch })(DataPresenter);

现在您不必模拟钩子,您只需使用道具测试演示者即可:

Now you don't have to mock the hook, you can just test the presenter with a prop:

it('presents user', () => {
  const { queryByText } = render(<UserPresenter user={{name: 'Mary'}} />); // <-- Named export
  expect(queryByText('Mary')).toBeTruthy();
});

或者,您可以选择更高级别的集成测试:

Or, you have the option of a higher-level integration test:

it('fetches data', () => {
  fetchData.mockResolvedValue('Mary');
  const { queryByText } = render(<UserWithData />); // <-- Default export
  expect(queryByText('Mary')).toBeFalsy();
  return wait(() => {
    expect(queryByText('Mary')).toBeTruthy();
  });
});

如果您愿意,您甚至可以对钩子进行单元测试.

You can even unit test the hook if you like.

这篇关于如何在要测试的 React 组件中模拟自定义钩子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆