使用玩笑的反应单元测试失败

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 尝试模拟loadDataactions 文件内容,正如Ajeet 所述,当您的组件连接到redux-store 时,您需要为provider 提供商店 @AjeetShah 请检查我编辑的问题。我尝试了商店,但仍然没有出现错误。实际上,在这个页面中,功能就像加载数据并显示到数据网格。所以,这就是为什么要测试 loadData 函数是否正确调用的原因。并将所有数据存储到状态。可能有一段时间没有数据。 @Chandan。请检查我编辑的问题。我尝试了商店,但仍然没有出现错误。 您正在导出/导入 AccountComponent 的连接版本,因此该组件没有道具 loadData。这来自 Redux。 @AjeetShah 是正确的,您需要将其加载到 &lt;Provider&gt; 中。您可能会导出组件的未连接版本以进行测试,并将您的 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', () =&gt; ( 具有相同的action 文件位置

以上是关于使用玩笑的反应单元测试失败的主要内容,如果未能解决你的问题,请参考以下文章

React Native:在开玩笑的单元测试中更新上下文 api 值

createWriteStream 的 ('error') 上的开玩笑单元测试

开玩笑单元测试返回“MongoError:拓扑被破坏”

开玩笑的单元测试不会等待 axios 响应

开玩笑单元测试检查唯一值

Vue 路由器的注入在 Je​​st 单元测试期间失败