【问题标题】:Testing functions inside stateless React component with Enzyme使用 Enzyme 测试无状态 React 组件中的函数
【发布时间】:2019-08-06 22:30:03
【问题描述】:

我有一个无状态组件:

export default function TripReportFooter(props) {
  const { tripReport, user, toggleFavorite, navigation } = props;


  handleShare = async slug => {
    try {
      const result = await Share.share({
        message: `Check out this Trip Report:\n/p/${slug}/`
      });

      if (result.action === Share.sharedAction) {
        if (result.activityType) {
        } else {
          // shared
        }
      } else if (result.action === Share.dismissedAction) {
      }
    } catch (error) {
      alert(error.message);
    }
  };

  handleFavorite = async id => {
    const token = await AsyncStorage.getItem("token");
    toggleFavorite(id, token);
  };

  return (
    ... // handleFavorite and handleShare called with TouchableOpacities.
  );
}

它内部有两个函数,handleSharehandleFavorite。我想测试这些函数被调用了,还有handleFavorite调用了prop函数toggle favorite。

我试过wrapper.instance().handleFavorite(),但由于它是一个无状态组件,它返回null

接下来 Stack Overflow 上的某个人建议使用这样的间谍:

    wrapper = shallow(<TripReportFooter {...props} handleFavorite={press} />);
    wrapper
      .find("TouchableOpacity")
      .at(0)
      .simulate("press");
    expect(press.called).to.equal(true);

但这返回了

'TypeError: 无法读取属性'equal' of undefined'。

调用这些函数的正确方法是什么?

【问题讨论】:

  • 不是答案,只是观察到您得到了TypeError: Cannot read property 'equal' of undefined,因为.to.equal(true)Chai 语法。由于您使用的是Jest,它应该是.toBe(true)
  • 你能把你的测试用例贴在这里codesandbox.io/s/m50o1ok8o9并发回网址吗?
  • 不需要先获取实例吗?包装器。实例()?不确定。这就是我在类组件上测试函数的方式,但是我在函数式组件中遇到了问题,因为它们显然没有暴露出来。
  • 这两个函数是如何触发的?请编辑您的帖子,添加更多代码

标签: reactjs react-native jestjs enzyme


【解决方案1】:

您首先需要考虑要测试什么。是实现细节还是与组件的交互?后者是一种更好的思维方式和立场,所以我要做的就是从交互的角度测试组件。

我愿意(对于handleShare):

  1. 模拟在 share 函数内部调用的 Share 对象方法;
  2. 选择我想点击/触摸的按钮
  3. 点击/触摸按钮
  4. 断言方法已被调用。

现在是handleFavorite

  1. 模拟AsyncStorage.getItem;
  2. 创建一个假的 toggleFavorite 函数,我将其作为道具传递;
  3. 选择我想点击/触摸的按钮
  4. 点击/触摸按钮
  5. 断言我的toggleFavorite 函数已被调用

如果您想单独测试这些功能,您必须将它们提取到组件外部并单独测试它们。但我不建议这样做,因为它不干净且需要额外的工作。

希望对您有所帮助!

【讨论】:

    【解决方案2】:

    功能组件中的功能未在原型或功能组件实例上定义,您不能直接监视它们

    这里的解决方案是测试各个函数的内部实现

    例如,对于handleFavourite 函数,您可以模拟 AsynStorage 并为 toggleFavourite 传递一个模拟函数,然后在 TouchableOpacity onPress 模拟上调用它

    您可以在这篇文章中查看如何模拟 AsyncStore: How to test Async Storage with Jest?

    const mocktToggleFavourite = jest.fn();
    wrapper = shallow(<TripReportFooter {...props} toggleFavourite={mocktToggleFavourite} />);
        wrapper
          .find("TouchableOpacity")
          .at(0)
          .simulate("press");
        expect(mockToggleFavourite).toHaveBeenCalled();
    

    同样,您可以通过首先模拟 Share.share 然后检查每个条件来测试 handleShare 中的各个功能。例如,您可以在 window.alert 上添加一个间谍并查看它是否被调用

    const windowSpy = jest.spyOn(window, 'alert');
    wrapper = shallow(<TripReportFooter {...props} toggleFavourite={mocktToggleFavourite} />);
    //Simulate event that calls handleShare
    // Mock Share to give required result
    expect(windowSpy).toBeCalledWith(expectedValue);
    

    【讨论】:

    • 如果我们要测试函数的返回值怎么办?例如toCamelcase()
    • @johannchopin 在这种情况下,您会看到返回值正在被另一个函数使用,并将用于更新状态或调用父函数。然后的想法是不测试返回值的函数,而是测试接受该函数返回值的函数。编写这样一个测试用例将确保您的两个功能都被覆盖
    • 是的,这适用于糟糕的逻辑,但如果我有多个链接函数,如 toMyStringFormat(),调用 toMyCamelCasel(),调用 toMyLowercase(),仅测试 toMyStringFormat() 的结果并不准确。如果测试失败,我们不知道错误的确切来源
    • 如果您提供此问题的答案,您将获得bounty :)
    • @johannchopin 我希望有一个解决方案。将很快研究它。如果我找到任何东西会通知你
    猜你喜欢
    • 1970-01-01
    • 2019-01-28
    • 1970-01-01
    • 1970-01-01
    • 2019-06-25
    • 1970-01-01
    • 2018-10-21
    • 2017-11-30
    • 2017-02-12
    相关资源
    最近更新 更多