天天看點

React 16 Jest單元測試 之 Mock Functions (Mocking Modules 和 Mock Implementations)React16 Jest單元測試 之 Mock Functions(Mocking Modules 和 Mock Implementations)

轉載

React16 Jest單元測試 之 Mock Functions(Mocking Modules 和 Mock Implementations)

項目初始化【這裡使用之前的項目,節省時間】

項目初始化位址

https://github.com/durban89/webpack4-react16-reactrouter-demo.git               
tag:v_1.0.21           

拉取

git clone         https://github.com/durban89/webpack4-react16-reactrouter-demo.git                
cd webpack4-react16-reactrouter-demo
git fetch origin
git checkout v_1.0.21
npm install            

Mocking Modules

假設我們有一個從API中擷取使用者的類。該類使用axios調用API然後傳回包含所有使用者的data屬性:

因為要用到axios,需要安裝下axios,

運作

npm install axios --save           

然後建立檔案src/lib/user.js

import axios from 'axios';

class Users {
  static all() {
    return axios.get('/user.json').then(resp => resp.data);
  }
}

export default Users;           

建立檔案src/__tests__/user.test.js

import axios from 'axios';
import Users from '../lib/user';

jest.mock('axios');

test('should fetch users', () => {
  const resp = {
    data: [
      {
        name: 'Durban',
      },
    ],
  };

  axios.get.mockResolvedValue(resp);
  // 或者也可以使用下面的代碼
  // axios.get.mockImplementation(() => Promise.resolve(resp));


  return Users.all().then(users => expect(users).toEqual(resp.data));
});           

現在,為了不在實際通路API的情況下測試此方法(進而建立緩慢且脆弱的測試),我們可以使用jest.mock(...)函數自動模拟axios子產品。

一旦我們模拟了子產品,我們就可以為.get提供一個mockReturnValue,它傳回我們測試希望要的斷言資料。實際上,我們說我們希望axios.get('/users.json')傳回一個假響應。

Mock Implementations

盡管如此,有些情況下超出指定傳回值的能力和全面替換模拟函數的實作是有用的。這可以使用jest.fn或mock函數上的mockImplementationOnce方法來實作。如下

const myMockFn = jest.fn(cb => cb(null, true));

myMockFn((err, val) => console.log(val));
// > true
myMockFn((err, val) => console.log(val));
// > true           

當需要定義從另一個子產品建立的模拟函數的預設實作時,mockImplementation方法很有用,如下

// foo.js
module.exports = function() {
  // some implementation;
};

// test.js
jest.mock('../foo'); // this happens automatically with automocking
const foo = require('../foo');

// foo is a mock function
foo.mockImplementation(() => 42);
foo();
// > 42           

當需要重新建立模拟函數的複雜行為,以便多個函數調用産生不同的結果時,請使用mockImplementationOnce方法,如下

const myMockFn = jest
  .fn()
  .mockImplementationOnce(cb => cb(null, true))
  .mockImplementationOnce(cb => cb(null, false));

myMockFn((err, val) => console.log(val));
// > true

myMockFn((err, val) => console.log(val));
// > false           

當mocked函數超出了mockImplementationOnce定義的實作次數時,它将使用jest.fn執行預設實作集(如果已定義),如下

const myMockFn = jest
  .fn(() => 'default')
  .mockImplementationOnce(() => 'first call')
  .mockImplementationOnce(() => 'second call');

console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
// > 'first call', 'second call', 'default', 'default'           

對于我們有通常連結的方法(是以總是需要傳回這個)的情況,我們有一個含糖API,以.mockReturnThis()函數的形式簡化它,該函數也位于所有模拟上,如下

const myObj = {
  myMethod: jest.fn().mockReturnThis(),
};           

跟如下是類似的

const otherObj = {
  myMethod: jest.fn(function() {
    return this;
  }),
};           

項目實踐位址

https://github.com/durban89/webpack4-react16-reactrouter-demo.git               
tag:v_1.0.22