使用 Jest 进行测试时如何用 mock 替换 React 组件
How to replace a React component with a mock when testing with Jest
在我正在从事的项目中,我真的被困在这个问题上,我找到的所有答案似乎都很简单,但它们对我没有用。也许我真的不明白什么是模拟,我真的可以使用一些指导。
我正在测试一个 parent 组件,它有一个 child 组件,该组件使用 GraphQL 从数据库中获取一些数据。在测试 parent 时,我不关心 child 在做什么。我想用模拟组件(不从数据库获取数据的组件)替换 child,这样我就只能专注于 parent.
我想出了一个最简单的例子来说明我的情况。请注意,我使用的是 React Native 和 React Native 测试库。
./src/ParentComponent.js
import React from 'react';
import { Text, View } from 'react-native';
import ChildComponent from './ChildComponent';
const ParentComponent = () => (
<View>
<Text>Hello World</Text>
<ChildComponent />
</View>
);
export default ParentComponent;
./src/ChildComponent.js
import React from 'react';
import { useQuery } from 'react-apollo';
import { View, Text } from 'react-native';
import gql from 'graphql-tag';
const CURRENT_USER_QUERY = gql`
query {
currentUser {
username
}
}
`;
const ChildComponent = () => {
const { data } = useQuery(CURRENT_USER_QUERY);
const { username } = data.currentUser;
return (
<View>
<Text>Welcome, {username}</Text>
</View>
);
};
export default ChildComponent;
./src/__mocks__/ChildComponent.js
import React from 'react';
import { Text } from 'react-native';
const ChildComponent = () => <Text>Welcome.</Text>;
export default ChildComponent;
./src/ParentComponent.test.js
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { render } from '@testing-library/react-native';
import ParentComponent from '../ParentComponent';
it(`should render the parent component.`, () => {
jest.mock('../ChildComponent');
const { getByText } = render(
<MockedProvider>
<ParentComponent />
</MockedProvider>
);
expect(getByText('Hello World')).toBeTruthy();
});
当我运行测试时,出现以下错误...
● should render the parent component.
TypeError: Cannot read property 'currentUser' of undefined
14 | const ChildComponent = () => {
15 | const { data } = useQuery(CURRENT_USER_QUERY);
> 16 | const { username } = data.currentUser;
| ^
17 |
18 | return (
19 | <View>
at ChildComponent (src/ChildComponent.js:16:29)
还在用真正的<ChildComponent />
。为什么不将 <ChildComponent />
替换为 __mocks__
目录中的模拟版本?这不是模拟的工作方式吗?如果有人可以帮助和解释,将不胜感激。谢谢。
在为此绞尽脑汁几天后,我终于弄清楚出了什么问题。我在 it
声明中调用模拟。当我将行 jest.mock('../ChildComponent');
移动到顶部时,一切正常。所以,测试文件应该是这样的...
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { render } from '@testing-library/react-native';
import ParentComponent from '../ParentComponent';
jest.mock('../ChildComponent');
it(`should render the parent component.`, () => {
const { getByText } = render(
<MockedProvider>
<ParentComponent />
</MockedProvider>
);
expect(getByText('Hello World')).toBeTruthy();
});
在我正在从事的项目中,我真的被困在这个问题上,我找到的所有答案似乎都很简单,但它们对我没有用。也许我真的不明白什么是模拟,我真的可以使用一些指导。
我正在测试一个 parent 组件,它有一个 child 组件,该组件使用 GraphQL 从数据库中获取一些数据。在测试 parent 时,我不关心 child 在做什么。我想用模拟组件(不从数据库获取数据的组件)替换 child,这样我就只能专注于 parent.
我想出了一个最简单的例子来说明我的情况。请注意,我使用的是 React Native 和 React Native 测试库。
./src/ParentComponent.js
import React from 'react';
import { Text, View } from 'react-native';
import ChildComponent from './ChildComponent';
const ParentComponent = () => (
<View>
<Text>Hello World</Text>
<ChildComponent />
</View>
);
export default ParentComponent;
./src/ChildComponent.js
import React from 'react';
import { useQuery } from 'react-apollo';
import { View, Text } from 'react-native';
import gql from 'graphql-tag';
const CURRENT_USER_QUERY = gql`
query {
currentUser {
username
}
}
`;
const ChildComponent = () => {
const { data } = useQuery(CURRENT_USER_QUERY);
const { username } = data.currentUser;
return (
<View>
<Text>Welcome, {username}</Text>
</View>
);
};
export default ChildComponent;
./src/__mocks__/ChildComponent.js
import React from 'react';
import { Text } from 'react-native';
const ChildComponent = () => <Text>Welcome.</Text>;
export default ChildComponent;
./src/ParentComponent.test.js
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { render } from '@testing-library/react-native';
import ParentComponent from '../ParentComponent';
it(`should render the parent component.`, () => {
jest.mock('../ChildComponent');
const { getByText } = render(
<MockedProvider>
<ParentComponent />
</MockedProvider>
);
expect(getByText('Hello World')).toBeTruthy();
});
当我运行测试时,出现以下错误...
● should render the parent component.
TypeError: Cannot read property 'currentUser' of undefined
14 | const ChildComponent = () => {
15 | const { data } = useQuery(CURRENT_USER_QUERY);
> 16 | const { username } = data.currentUser;
| ^
17 |
18 | return (
19 | <View>
at ChildComponent (src/ChildComponent.js:16:29)
还在用真正的<ChildComponent />
。为什么不将 <ChildComponent />
替换为 __mocks__
目录中的模拟版本?这不是模拟的工作方式吗?如果有人可以帮助和解释,将不胜感激。谢谢。
在为此绞尽脑汁几天后,我终于弄清楚出了什么问题。我在 it
声明中调用模拟。当我将行 jest.mock('../ChildComponent');
移动到顶部时,一切正常。所以,测试文件应该是这样的...
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { render } from '@testing-library/react-native';
import ParentComponent from '../ParentComponent';
jest.mock('../ChildComponent');
it(`should render the parent component.`, () => {
const { getByText } = render(
<MockedProvider>
<ParentComponent />
</MockedProvider>
);
expect(getByText('Hello World')).toBeTruthy();
});