使用jest + enzyme进行测试,无理由地调用mock函数两次

问题描述 投票:2回答:2

我正在努力学习Jest和Enzyme,但是我遇到了一个问题,我找不到解决方案,这是我的测试......我知道这不是很好,但我正在学习:

import * as apiMock from '../api';

const fakePostId = '1';
const fakePersona = 'Fake';

jest.mock('../api', () => {
    return {
        fetchAllComments: jest.fn(() => {
            return [];
        }),
        filterComments: jest.fn(() => {
            return [];
        }),
        createCommentObject: jest.fn(() => {
            return [];
        }),
    };
});

test('checks if functions are called after didMount', () => {
    const component = shallow(
        <Comments postId={fakePostId} currentPersona={fakePersona} />
    );

    const spySetComments = jest.spyOn(
        component.instance(),
        'setCommentsFromLocalStorage'
    );

    component.instance().componentDidMount();

    expect(spySetComments).toHaveBeenCalledTimes(1);

    //Don't know why these are called 2! times, I can't see why removing componentDidMount makes it 0.
    expect(apiMock.fetchAllComments).toHaveBeenCalledTimes(1);
    expect(apiMock.filterComments).toHaveBeenCalledTimes(1);
}

问题是toHaveBeenCalledTimes(1)失败的原因:

预期的模拟函数已被调用一次,但它被调用了两次。

但我不知道为什么。 setCommentsFromLocalStorage只运行一次,这是sohuld从componentDidMount运行并执行这些api调用一次的函数。

ReactComponent looks like this:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import CreateNewComment from './CreateNewComment';
import SingleComment from './SingleComment';
import * as api from '../api';

class Comments extends Component {
  state = {
    comments: []
  };

  componentDidMount() {
    this.setCommentsFromLocalStorage();
  }

  setCommentsFromLocalStorage = (postId = this.props.postId) => {
    const fetchedComments = api.fetchAllComments();
    const comments = api.filterComments(fetchedComments, postId);
    this.setState({ comments });
  };

  removeComment = commentId => {
    api.removeComment(commentId);
    this.setCommentsFromLocalStorage();
  };

  renderCommentList = (comments, currentPersona) =>
    comments.map(comment => (
      <SingleComment
        {...comment}
        currentPersona={currentPersona}
        key={comment.id}
        onClick={this.removeComment}
      />
    ));

  render() {
    return (
      <div className="py-2">
        <h2 className="text-indigo-darker border-b mb-4">Comments</h2>
        {this.renderCommentList(this.state.comments, this.props.currentPersona)}
        <CreateNewComment
          postId={this.props.postId}
          author={this.props.currentPersona}
          updateComments={this.setCommentsFromLocalStorage}
        />
      </div>
    );
  }
}

Comments.propTypes = {
  postId: PropTypes.string.isRequired,
  currentPersona: PropTypes.string.isRequired
};

export default Comments;
javascript reactjs jestjs enzyme
2个回答
1
投票

componentDidMountshallow()期间被召唤。


这意味着setCommentsFromLocalStorage被调用,在最初的fetchAllComments调用期间调用filterCommentsshallow()

api已被嘲笑,所以它记录了对fetchAllCommentsfilterComments的调用。


一旦发生这一切,就会为setCommentsFromLocalStorage创建间谍,再次调用componentDidMount(再次调用fetchAllCommentsfilterComments)。

setCommentsFromLocalStorage的间谍然后正确地报告它被调用一次(因为它仅在第二次调用componentDidMount期间存在)。

fetchAllCommentsfilterComments的间谍然后正确地报告他们被称为两次,因为他们在两次打电话给componentDidMount时都存在。


修复测试的最简单方法是在调用fetchAllComments之前清除filterCommentscomponentDidMount上的模拟:

apiMock.fetchAllComments.mockClear();  // clear the mock
apiMock.filterComments.mockClear();  // clear the mock

component.instance().componentDidMount();

expect(spySetComments).toHaveBeenCalledTimes(1);  // SUCCESS
expect(apiMock.fetchAllComments).toHaveBeenCalledTimes(1);  // SUCCESS
expect(apiMock.filterComments).toHaveBeenCalledTimes(1);  // SUCCESS

0
投票

使用beforeEachafterEach分别模拟和mockRestore间谍。

这在Jest docs的Setup and Teardown部分中有解释。

© www.soinside.com 2019 - 2024. All rights reserved.