Jest:每个测试模拟一个函数不起作用

时间:2018-02-27 09:58:36

标签: reactjs unit-testing react-native mocking jestjs

在我的react-native应用程序中,我想向我的服务器发送一个帖子请求,并根据结果,我想显示一条消息。我想用jest对它进行单元测试,嘲笑后端的调用。

我尝试创建一个最小的示例来显示正在发生的事情:

这是我正在测试的组件

import React from 'react';
import { Alert } from 'react-native';
import { create } from 'apisauce';

const api = create({ baseURL: "someurl" });

export class ApisauceExample extends React.Component {

  upload() {
    api.post('/upload')
      .then(() => { Alert.alert('Success!', 'Thanks, dude!' ); })
      .catch(() => { Alert.alert('Error!', 'Something went wrong!' ); });
  }

  render() {
    this.upload();
    return null;
  }
}

到目前为止,这么容易。让我用单元测试测试正面POST行为,我在模拟模块:

使用全局模拟的工作单元测试:

import React from 'react';
import Adapter from 'enzyme-adapter-react-16';
import { configure, shallow } from 'enzyme';
import { ApisauceExample } from '../src/ApisauceExample';

configure({ adapter: new Adapter() });

const mockAlert = jest.fn();
jest.mock('Alert', () => ({
  alert: mockAlert
}));

let mockPostResult = jest.fn();
jest.mock('apisauce', () => ({
  create: () => ({
    post: (url) => new Promise((resolve) => {
      mockPostResult(url);
      resolve();
    })
  })
}));

describe('ApisauceExample', () => {
  it('should call create and alert', async () => {
    await shallow(<ApisauceExample />);
    expect(mockPostResult).toHaveBeenCalledTimes(1);
    expect(mockAlert).toHaveBeenCalledWith('Success!', 'Thanks, dude!');
  });
});
是的,这完美无缺。但现在,我想测试我的代码在成功的POST和不成功的POST中是否正常运行。我了解到你可以使用mockImplementation函数通过jest更改模拟。 (参见例如Jest Mock module per test)。 我已经在其他测试中使用过它,但在这里它根本不起作用:

每个测试用例不具有不同模拟行为的单元测试

import React from 'react';
import Adapter from 'enzyme-adapter-react-16';
import { configure, shallow } from 'enzyme';
import { ApisauceExample } from '../src/ApisauceExample';

configure({ adapter: new Adapter() });

const mockAlert = jest.fn();
jest.mock('Alert', () => ({
  alert: mockAlert
}));

jest.mock('apisauce', () => ({
  create: jest.fn()
}));
import { create } from 'apisauce';

describe('ApisauceExample2', () => {
  it('should call create and alert', async () => {
    create.mockImplementation(() => ({
      post: (url) => new Promise((resolve, reject) => {
        reject("error");
      })
    }));
    await shallow(<ApisauceExample />);
    expect(mockAlert).toHaveBeenCalledWith('Error!', 'Something went wrong!');
  });
});

这导致:

Failed: Cannot read property 'post' of undefined
  TypeError: Cannot read property 'post' of undefined
  at ApisauceExample.upload (src/ApisauceExample.js:10:4)
  at ApisauceExample.render (src/ApisauceExample.js:16:6)

我只是不明白发生了什么。在我看来,第二个模拟与第一个模拟相同(除了拒绝而不是解决)。

你看到这里发生了什么吗?我真的很感激任何提示。

非常感谢,祝你有愉快的一天!

1 个答案:

答案 0 :(得分:0)

尝试将axios-mock-adapter添加到您的设置中, 并记住模拟api.apisauce.axiosInstance而非API(apisauce通过api.apisauce.axiosInstance公开内部axios实例

如此:

test('mock adapter', async () => {
  const api = API.create()
  const mock = new MockAdapter(api.axiosInstance)
  mock.onGet('/someEndpoint').reply(201, {
    re: 'superstar'
  })
  const response = await api.getSomeEndpoint()
  expect(response.ok).toBe(true)
  expect(response.status).toBe(201)
  expect(response.data).toEqual({ re: 'superstar' })
})

和您的api

import apisauce from 'apisauce'

...一些代码

const create = (baseURL = 'https://api.github.com/') => {
  const api = apisauce.create()
  const getSomeEndpoint = () => api.get('some_endpoint')

  return {
    getSomeEndpoint,
    axiosInstance: api.axiosInstance
  }
}

export default {
  create
}