繁体   English   中英

用Jest / Enzyme&Axios测试React组件

[英]Testing a React component with Jest / Enzyme & Axios

我有一个使用Axios来获取数据的react组件:

import React from "react";
import axios from "axios";

export default class Example extends React.Component {
    constructor() {
        super();
        axios("http://localhost/data.json").then(response => {
            this.setState({
                data: response.data
            });
        });
    }

    render() {
        return <ul>{this.data.map(item => <li>{item}</li>)}</ul>;
    }
}

我正在尝试围绕此组件编写一些基本测试。 首先,我只是想渲染组件...

import React from "react";
import { shallow } from "enzyme";

import Example from "./example";

it.only("Renders", () => {
    const wrapper = shallow(<Example />);
    const li = wrapper.find("li");
    expect(li.length).toBe(2); // there are two items in the data file
});

...但是我得到的第一件事是来自axios的网络错误。

我是测试的新手,我知道要进行模拟等所需的组件测试,但是我给您的印象是,尽管它不是最佳选择,但您仍然可以使用实时端点。

有没有一种方法可以让Jest等待组件渲染之后再进行断言?

任何意见,将不胜感激!

我使用间谍( sinonjs )通过异步调用来测试代码。 带有间谍的想法是“监视”特定功能(即您的回叫),并断言是否被调用和/或被调用了多少次,等等。

测试间谍是一个函数,它记录参数,返回值,该值以及所有调用所引发的异常(如果有)。

let wrapper = shallow(<ReactComponent/>);
let handleEventSpy = sinon.spy(ReactComponentFile, 'functionName');

it('Event Handled', () => {
  const event = {... event stuffs ...};
  expect(handleEventSpy.called).tobe(false);
  wrapper.simulate('Event', event);
  expect(handleEventSpy.called).tobe(true)
}

您还可以使用Mocha测试异步函数,该想法是包装称为async函数的代码,并向其传递一个特殊函数,该函数可以在async函数完成后调用该函数。 摩卡(mocha)在诺言方面也能很好地工作,并且语法更加清晰。

我建议:

  1. 将响应处理程序分解为自己的函数
    • 允许使用特定测试数据与axios隔离进行测试
    • 根据数据更新的频率,可以提高性能,而不是在每次调用时都绑定新功能
  2. 将列表渲染器分解成自己的功能
    • 同上
    • 与生命周期挂钩结合使用,避免在null对象上调用map函数
  3. 利用React的组件生命周期挂钩
  4. 虽然不是必需的,它是通过好的做法props在构造函数中的父类
  5. 如建议的那样,模拟axios进行测试以避免执行长时间运行的异步任务,而应使用测试数据对象。
    • jest.mock('axios');

import React from "react";
import axios from "axios";

export default class Example extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    axios("http://localhost/data.json")
      .then(response => this.responseHandler)
      .catch(err => this.errorHandler);
  }

  responseHandler = ({data}) => this.setState({data});
  errorHandler = (err) => { ... handle error ...};
  renderRows = ({data}) = <>{data.map(item => this.renderRow}</>; // React Fragment, fyi
  renderRow = (item) => <li>{item}</li>;

  render() {
    return <ul>{this.renderRows(this.state)}</ul>;
  }
}

通过进一步分解组件,可以编写更简单的测试,通过将处理程序与axios调用分开,则可以使用测试数据。 您不是要测试您的API,对吗?

通常,您永远都不想在Javascript的构造函数中进行异步调用。 这是一种反模式,因为当构造函数返回时,您创建的对象处于不确定状态。

在React中,调用异步函数的初始化代码通常进入componentDidMount生命周期方法中。

如果您从componentDidMount返回承诺,则Enzyme将在渲染期间等待该承诺解决。

当然,您将需要模拟axios,以便在测试期间没有网络呼叫。 您可以通过在测试文件中调用jest.mock('axios')来实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM