【问题标题】:Jest async function开玩笑的异步功能
【发布时间】:2019-01-02 01:04:46
【问题描述】:

我是 jest/enzyme 的新手,我尝试测试一个函数。该测试试图测试getData() 设置了状态中返回的数组。

这就是它的样子:

getData () {
  axios.get('http://localhost:8080/targeting-data').then(response => {
    this.setState({
      targetingData: response.data,
      load: true
    })
  })
}

componentDidMount () {
  this.interval = setTimeout(() => {
    this.getData()
  }, 3000)
}

我的第一次测试:

import FormWrapper from './../containers/FormWrapper/FormWrapper'

const mockGetData = jest.spyOn(FormWrapper.prototype, 'getData')

it('testing', () => {
  mockGetData()
  expect(formWrapper.state().targetingData).toHaveLength(8)
})

我失败了:

expect(received).toHaveLength(length)

Expected value to have length:
  8
Received:
  []
received.length:
  0

我的第二个测试:

it('getDataFunc', (done) => {
  mockGetData().then(res => {
    expect(res).toHaveLength(8)
    done()
  })
})

我失败了:

TypeError: Cannot read property 'then' of undefined

(node:6302) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'setState' of undefined
(node:6302) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 4)

我对如何测试它感到困惑,如果有任何建议,我都会很高兴。谢谢

【问题讨论】:

  • jestjs.io/docs/en/tutorial-async 这可能对你有帮助。
  • 欢迎来到 Stack Overflow。有多种模拟远程 API 调用的选项,因此您无需修改​​代码即可对其进行测试
  • 感谢您的建议@varit05。但我仍然对如何实现它感到困惑
  • 嗨@Mikkel你能告诉我其中一个吗?
  • 可能相同(或至少非常接近):stackoverflow.com/questions/51876091/…

标签: javascript reactjs unit-testing jestjs enzyme


【解决方案1】:

您可以使用async/await 方法来测试您的函数getData,因为它是async,但首先您需要模拟axios get 方法,因为您不想在测试中包含外部API 调用,而只是模拟它的响应:

import React from 'react';
import axios from 'axios';
import {shallow, mount} from "enzyme";
import FormWrapper from './../containers/FormWrapper/FormWrapper'

jest.mock('axios'); // for mocking axios

it('test', async () => {
    const wrapper = shallow(<FormWrapper />); // I'm using shallow render, you could use mount if you want to
    const instance = wrapper.instance(); // get an instance in order to call getData() directly
    // mock axios get with a response
    axios.get.mockImplementation(() => Promise.resolve([
        {
            id: 1,
            val: 'val1'
        },
        {
            id: 2,
            val: 'val2'
        }
    ]));
    await instance.getData();
    expect(wrapper.state().targetingData).toHaveLength(2); // this is the length of the mocked response I have added here
});

关于这个功能,我想在这里指出一些事情。在我看来,您尝试测试的函数getData() 实际上并不是一个很好的测试对象,因为它不包含您编写的任何逻辑。

它从 API 获取一些数据(这不是你拥有的东西),然后它使用 this.setState 来设置状态(并且你不想测试 React 执行 setState 来更新你的状态的行为)。

如果您想让state 填充一些数据以用于测试组件中的其他功能,那么我建议您像这样手动设置它:

const wrapper = shallow(<FormWrapper />);
wrapper.setState({
    targetingData: {...}
});

这样您就可以更专注于包含更多您自己编写的逻辑的函数和代码部分。

【讨论】:

  • 其实函数里面有一些逻辑,我其实是需要setState来测试的
  • 好的,按照我在答案中解释的方式进行。
猜你喜欢
  • 2020-10-08
  • 2017-07-14
  • 1970-01-01
  • 2018-09-25
  • 1970-01-01
  • 2018-02-22
  • 2018-06-11
  • 1970-01-01
  • 2019-05-08
相关资源
最近更新 更多