useQuery:无法监视 useQuery 属性 因为它不是函数

useQuery: Cannot spy the useQuery property because it is not a function

像这样简单使用查询

  const {
    isLoading, isError, data,
  } = useQuery(['courses', { userId: someUserId }], fetchDataFromBackendServer);

在我的单元测试中,我希望从一开始就使用 useQuery return 信息(我想这样做是有原因的,但这不是主题)

  describe.only('Title', () => {
    beforeEach(() => {
      jest.clearAllMocks();
      jest.spyOn(React, 'useQuery').mockResolvedValue({ isError: false, isLoading: false });
    }
    ...
  }

它给我:无法监视 useQuery 属性 因为它不是一个函数;改为未定义

请问如何解决这个问题?

首先,React不提供useQuery hook。

我想你正在使用 react-query

第二,如果你想使用jest.spyOn(obj, 'method'),你不能从obj中析构方法。这意味着您应该在组件中像 ReactQuery.useQuery() 一样使用它。

例如

import { render } from '@testing-library/react';
import React from 'react';
import * as ReactQuery from 'react-query';

describe('70660790', () => {
  test('should pass', () => {
    jest.spyOn(ReactQuery, 'useQuery').mockImplementation();
    function Test() {
      ReactQuery.useQuery('todos');
      return null;
    }
    render(<Test />);
    expect(ReactQuery.useQuery).toBeCalledWith('todos');
  });
});

测试结果:

 PASS  examples/70660790/index.test.tsx (11.646 s)
  70660790
    ✓ should pass (18 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        13.036 s

查看react-query exports如何在桶文件中挂钩,我们必须使用名称空间导入。

最后,不要mock useQuery第三方包提供的hook,测试实现细节。您应该继续使用原始的 useQuery 钩子和模拟副作用函数,例如 fetchDataFromBackendServer(我想这是对远程服务器的 API 调用)。然后你可以测试组件的输出是什么。 参见 testing

再次声明,不推荐mock useQuery。模拟实现可能与原始实现不一致,这将导致您的测试构建在错误的模拟实现之上。这会导致您的测试用例通过,但程序在运行时不正确。

而且,测试实现细节也会使测试用例容易受到攻击。 实现细节的一个小改动都会导致测试用例失败,您将不得不修改测试用例。