「CI集成」基于Jest Mock API对业务逻辑集成测试

有时候咱们须要不发送请求就能完成前端的业务逻辑测试,而许多的业务逻辑都会须要调用到后端的API接口。那如何能mock咱们所须要的data就是一个问题。当咱们能有一个良好的测试环境以后,只要保证后端的接口没有问题,那咱们就能够保证业务逻辑也没有问题。javascript

因此咱们对API的集成测试有如下几个要求前端

1.不发送请求,返回本地假数据java

2.发布前经过CI跑unit test,经过则发布上线git

如何实现?

首先通常咱们在network部分都会进行封装,假设在project中封装了以下的请求工具github

// http tool
export default function http() {
    // some implement
}
复制代码

既然咱们不能发送真实请求,那咱们就须要相似能拦截的东西,拦截也能够经过mock代替。因而咱们能够经过jest.mock方法来作。后端

jest.mock

// api/http.js
// real fn
export default function http() {
    console.log('real');
    //...
}
复制代码
// api/__mocks__/http.js
// fake fn
export default function http() {
    console.log('fake');
}
复制代码
// some.test.js
jest.mock('../http')
import http from '../http'
http() // 这里log的是fake,而不是real
复制代码

这个就是jest.mock的做用。api

正事

明白了这个后就好办了。项目目录以下:安全

-- api
    |-- __mockData__
        |-- user.data.js
    |-- __mocks__
        |-- http.js
    |-- __tests__
        |-- user.test.js
    |-- http.js
    |-- profile // profile 业务模块
        |-- user.js // 获取用户信息
复制代码

而咱们的fake文件其实主要作的事情就是根据请求url,method,status等,去读取对应的本地假数据。大体以下。数据结构

// ./api/__mocks__/http.js
// 直接读取本地假数据
let statusCode;
export function setStatus(code) {
  statusCode = code;
}

export default function http({ url = "", data = {}, method = "get" }) {
  return new Promise((resolve, reject) => {
    const lastSlash = url.lastIndexOf("/");
    const module = url.substring(lastSlash + 1);
    const mockData = require(`../__mockData__/${module}.data`).default;
    const result = mockData[`${method.toUpperCase()} ${statusCode}`];

    process.nextTick(
      () => (statusCode === 200 ? resolve(result) : reject(result))
    );
  });
}

复制代码

mockData文件夹则就是放咱们的假数据,在这咱们能够假设定义以下数据结构,来模拟咱们的responseasync

// ./api/__mockData__/user.js
export default {
  'GET 200': {
    code: 0,
    msg: 'ok',
    data: {
      username: '二哲',
      age: 18,
    },
  },
  'POST 200': {
    code: 0,
    msg: 'xxx',
  },
  'GET 400': {
    msg: 'invald params',
    code: -1,
  },
  'GET 401': {},
};
复制代码

最后看下咱们的 unit test 如何写

// ./api/__test__/user.test.js
jest.mock('../http') // jest 会自动搜索目录下的 __mocks__里的文件
import http from '../http';

describe('user api test', () => {
    it("user GET should be 200", async () => {
    setStatus(200);

    const result = await http({
      url,
      method: "get"
    });
    expect(result.data.username).toBe("Kodo");
  });

})
复制代码

实现了这个有什么用?

假设/user接口返回得数据多是这样

{
    "username": "二哲",
    "age": 18,
}
复制代码

而咱们前端service层为UI层提供了一个initUserData的方法,initUserData方法里的操做是当age为18,那就要返回19。

因此咱们在Jest则能够直接这样测试

// ./api/__test__/user.test.js
jest.mock('../http') // jest 会自动搜索目录下的 __mocks__里的文件
import { setStatus } from './http';
import { initUserData } from '../user'

describe('user api test', () => {
  it("if user age is 18, age should be 19", async () => {
    expect.assertions(1);
    setStatus(200);
    const result = await initUserData();
    // console.log(result);
    expect(result.data.age).toBe(19);
  });
  
  // test catch
  it("initUserData 400", async () => {
    expect.assertions(1);
    setStatus(400);
    const result = await initUserData();
    expect(result.msg).toBe("invald params");
  });
  
})
复制代码

这样咱们使用Jest就能够完成对业务逻辑的测试,Unit test在大型项目中很是须要,每当提交一个feature时,能够跑完全部测试,会让你很是有安全感,极大提高了项目的稳定性。

TIP

真正的方法(http),与mock的方法http,文件必须同名,而后放在mocks文件夹下便可。若是不一样名使用jest.mock()则会失败。

以上例子都在这 jest-api-test

相关文章
相关标签/搜索