使用玩笑的反应单元测试失败
Posted
技术标签:
【中文标题】使用玩笑的反应单元测试失败【英文标题】:React Unit test using jest failed 【发布时间】:2021-08-27 10:18:18 【问题描述】:我正在用玩笑和酶进行单元测试。我有以下带有钩子的连接组件。 我调用了 redux 操作来加载数据。
import React, useEffect, useState, useCallBack from "react";
import connect from "react-redux";
import CustomComponent from "../Folder";
import loadData, createData, updateData from "../../redux/actions";
const AccountComponent = (props) =>
const total = 50;
const [aIndex, setAIndex] = useState(1);
const [arr, setArr] = useState(['ds,dsf']);
//... some state variables here
const getData = () =>
props.loadData(aIndex, total, arr);
useEffect(() =>
getData();
,[aIndex, total])
//some other useEffect and useCallback
return(
<React.Fragment>
<CustomComponent ...someParam/>
<div>
...
</div>
</React.Fragment>
)
const mapStateToProps = (state) =>
const param1, param2, parma3 = state.AccountData;
return
param1,
param2,
parma3
export default connect(mapStateToProps, loadData, createData, updateData )(AccountComponent)
在这里,像下面我为上面的组件创建了一些测试用例。
import AccountComponent from "../";
import React from "react";
import renderer from "react-test-renderer"
describe("AccountComponent component", () =>
const loadData = jest.fn();
let wrapper;
it("snapshot testing", () =>
const tree = renderer.create(<AccountComponent loadData=loadData />).toJSON();
expect(tree).toMatchSnapshot();
)
beforeEach(() =>
wrapper = shallow(<AccountComponent loadData=loadData />).instance();
);
it('should call loadData', () =>
expect(wrapper.loadData).toHaveBeenCalled();
);
)
但是,它没有通过并显示错误。
快照测试错误:
不变的违规元素类型无效:预期的字符串或类/函数
方法调用测试出错:
无法读取未定义的属性“loadData”。
Enzyme 内部错误:Enzyme 需要配置适配器,但没有找到。 ...
不知道是什么问题,因为我不擅长单元测试。
我正在使用 react-redux 7。
任何帮助将不胜感激。
编辑:
我也尝试过如下提供者。但是,没有帮助。
import Provider from "react-redux";
import createStore from "redux";
import reducer from "../../reducers";
const store = createStore(reducer);
it("snapshot testing", () =>
const tree = renderer.create(<Provider store=store><AccountComponent loadData=loadData /></Provider>).toJSON();
expect(tree).toMatchSnapshot();
)
beforeEach(() =>
wrapper = shallow(<Provider store=store><AccountComponent loadData=loadData /></Provider>).instance();
);
【问题讨论】:
我认为,您正在通过检查loadData
是否被调用来测试实现细节。您应该测试数据是否在屏幕上对最终用户可见(而不用担心它是如何加载的或调用哪个函数来加载它)。而且,您似乎正在测试一个与 Redux 存储连接的组件,但您在测试时没有提供存储。见redux.js.org/recipes/writing-tests
尝试模拟loadData
的actions
文件内容,正如Ajeet 所述,当您的组件连接到redux-store
时,您需要为provider
提供商店
@AjeetShah 请检查我编辑的问题。我尝试了商店,但仍然没有出现错误。实际上,在这个页面中,功能就像加载数据并显示到数据网格。所以,这就是为什么要测试 loadData 函数是否正确调用的原因。并将所有数据存储到状态。可能有一段时间没有数据。
@Chandan。请检查我编辑的问题。我尝试了商店,但仍然没有出现错误。
您正在导出/导入 AccountComponent
的连接版本,因此该组件没有道具 loadData
。这来自 Redux。 @AjeetShah 是正确的,您需要将其加载到 <Provider>
中。您可能会导出组件的未连接版本以进行测试,并将您的 loadData
函数作为应该可以工作的道具传递,但该测试没有提供足够的信息。
【参考方案1】:
当它是一个功能组件并且您使用钩子时,单元测试可能不适用于浅层渲染。您必须改用“renderHooks”来创建包装器。详情请参考https://react-hooks-testing-library.com/。
【讨论】:
【参考方案2】:如果您正在使用 react,它已经带有 @testing-library
,并且您不需要酶来进行快照测试。这就是我进行快照测试的方式。
import React, Suspense from "react";
import screen from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import AccountComponent from "../";
import store from "./store";// you can mock the store if your prefer too
describe("<AccountComponent />", () =>
test("it should match snapshot", async () =>
expect.assertions(1);
const asFragment = await render(
<Suspense fallback="Test Loading ...">
<Provider store=store>
<AccountComponent />
</Provider>
</Suspense>
);
expect(asFragment()).toMatchSnapshot();
);
);
【讨论】:
这里的Suspense
是什么?
抱歉,它是从react
导入的,我错过了。【参考方案3】:
当您在同一个文件中使用连接的组件时,您需要通过Provider
传递状态。此外,您需要配置您的酶。最后,当你使用 react 钩子时,你需要进行异步单元测试,因为效果是异步的。当您尝试检查是否调用了任何函数时,您需要“监视”它。
import configureStore from 'redux-mock-store';
import React from 'react';
import renderer from 'react-test-renderer';
import Enzyme, shallow from 'enzyme';
import Provider from 'react-redux';
import Adapter from 'enzyme-adapter-react-16';
import act from 'react-dom/test-utils';
import createSagaMiddleware from 'redux-saga';
import AccountComponent from '../AccountComponent';
import * as actions from '../../../redux/actions';
jest.mock('../../../redux/actions', () => (
loadData: jest.fn(),
createData: jest.fn(),
updateData: jest.fn(),
));
const loadData = jest.spyOn(actions, 'loadData');
// configure Enzyme
Enzyme.configure( adapter: new Adapter() );
const configureMockStore = configureStore([createSagaMiddleware]);
const initialState =
AccountData:
param1: 'param1',
param2: 'param2',
parma3: 'parma3 ',
,
;
const store = configureMockStore(initialState);
describe('AccountComponent component', () =>
let wrapper;
it('snapshot testing', () =>
const tree = renderer
.create(
<Provider store=store>
<AccountComponent />
</Provider>,
)
.toJSON();
expect(tree).toMatchSnapshot();
);
beforeEach(async () =>
await act(async () =>
wrapper = shallow(
<Provider store=store>
<AccountComponent />
</Provider>,
);
);
await act(async () =>
wrapper.update();
);
);
it('should call loadData', () =>
expect(loadData).toHaveBeenCalled();
);
);
请使用将在该组件中使用的属性模拟您的 AccountData
状态。另外,我不确定您的测试文件在哪里,因此您可能需要将导入路径从 '../../../redux/actions'
更改为您的操作文件路径。最后,我不确定您使用的是什么中间件,所以请随意填写以将import createSagaMiddleware from 'redux-saga';
替换为您的 redux 中间件。
【讨论】:
我收到错误消息。renderer .create(
。 "InVariant 违规 无效的钩子调用:钩子只能在体内调用..."
另外,这个问题。 import act from 'react-dom/test-utils';
是什么?
第一个错误 - reactjs.org/warnings/…。 Act doc:reactjs.org/docs/test-utils.html#act 如果没有完整的代码和 package.json 文件,很难找出您的问题
第二个。因为它在这里显示错误。 expect(loadData).toHaveBeenCalled()
预期的模拟函数已被调用。
确保import * as actions from '../../../redux/actions';
和jest.mock('../../../redux/actions', () => (
具有相同的action
文件位置以上是关于使用玩笑的反应单元测试失败的主要内容,如果未能解决你的问题,请参考以下文章
React Native:在开玩笑的单元测试中更新上下文 api 值