首页 > 解决方案 > Jest 酶模拟函数不适用于 toHaveBeenCalled 和 mock.calls.length

问题描述

我正在学习反应单元测试,我写了简单的测试用例,但它不起作用,我用谷歌搜索了很多,到处都看到相同的例子,这对我不起作用。我尝试了两种方式来HaveBeenCalled/mock.calls.length。

计数器正在增加,我知道我可以检查/测试计数器值以确定是否单击了按钮,但是如果没有任何计数器并且我只想确保按钮单击触发功能怎么办?

我知道如果我将此函数移动到其他文件然后将其导入,那么下面的测试将通过,因为我将该函数作为道具传递。但是,如果我想测试一个未导入且在同一个文件中的函数怎么办?

沙盒演示

import React from "react";
import "./Login.css";

class Login extends React.Component {
  state = {
    counter: 0
  };

  doLogin = (event) => {
    let { counter } = this.state;
    this.setState((prevstate) => ({ counter: prevstate.counter + 1 }));
    // console.log("Handle login button click");
  };

  render() {
    const { counter } = this.state;
    return (
      <table width="100%" border="0" cellPadding={4}>
        <tr>
          <td>
            <input type="text" name="username" placeholder="Username" />
          </td>
        </tr>
        <tr>
          <td>
            <input type="password" name="password" placeholder="Password" />
          </td>
        </tr>
        <tr>
          <td>
            <button onClick={this.doLogin}>LogIn</button>
            &nbsp;&nbsp;{counter}
          </td>
        </tr>
      </table>
    );
  }
}

export default Login;

测试用例

it("Handle login button click", () => {
  const mockOnClick = jest.fn();

  const wrapper = shallow(<Login onClick={mockOnClick} />);
  wrapper.find("button").simulate("click");
  wrapper.find("button").simulate("click");
  // mockOnClick();
  console.log(wrapper.state("counter"));
  // expect(mockOnClick).toHaveBeenCalled();
  expect(mockOnClick.mock.calls.length).toEqual(2);
});

标签: reactjsunit-testingjestjsenzyme

解决方案


因为onClick事件是在组件上button而不是在Login组件上,所以函数没有按照您期望的方式绑定。您实际上要做的是模拟组件,然后用伪造的函数替换该函数。

it("Handle login button click", () => {
  const mockOnClick = jest.fn();

  const wrapper = shallow( < Login / > );
  wrapper.instance().doLogin = mockOnClick;
  //MUST forceUpdate or the first .simulate call will trigger the real function.
  wrapper.instance().forceUpdate();  
  wrapper.find("button").simulate("click");
  wrapper.find("button").simulate("click");
  // mockOnClick();
  console.log(wrapper.state("counter"));
  // expect(mockOnClick).toHaveBeenCalled();
  expect(mockOnClick.mock.calls.length).toEqual(2);
});

https://codesandbox.io/s/amazing-easley-hd0hc

请注意,instance必须forceUpdate避免调用真正的函数。此外,这是用假函数替换函数而不是调用真实函数,因此只是测试onClick机制本身,这并不是对应用程序功能的真正有用测试。


推荐阅读