Axios 中的单元测试拦截器逻辑

Posted

技术标签:

【中文标题】Axios 中的单元测试拦截器逻辑【英文标题】:Unit test interceptor logic in Axios 【发布时间】:2019-05-30 04:04:12 【问题描述】:

我在 Axios 中设置了一个拦截器,如果初始 HTTP 响应是 401,它将刷新令牌,然后重试调用。

我正在尝试通过模拟 Axios 请求以返回 401,然后返回有效响应(请参阅下面的简化版本)并断言它被调用两次来对该逻辑进行单元测试。

我的问题是因为我在模拟请求,所以拦截器似乎没有运行。我没有重试请求,而是返回了stubAuthError

有什么方法可以实现我所追求的,或者有更好的方法来测试它吗?

index.js

const axios = require('axios');

axios.interceptors.response.use(
  response => response,
  error => 
    const status = error.response ? error.response.status : null;

    if (status === 401) 
      return makeRequest();
     else 
      return Promise.reject(error);
    
  
);

async function makeRequest() 
  return axios.request('url');


module.exports = 
  makeRequest
;

index.spec.js

const axios = require('axios');

const  makeRequest  = require('./index');

const stubAuthError =  response:  status: 401  ;
const stubResponse =  data:  foo: 'bar'  ;

it('should make the request twice', async () => 
  expect.assertions(1);

  axios.request = jest.fn();
  axios.request
    .mockRejectedValueOnce(stubAuthError)
    .mockResolvedValueOnce(stubResponse);

  try 
    await makeRequest();
   catch (error) 

  expect(axios.request).toHaveBeenCalledTimes(2);
);

【问题讨论】:

【参考方案1】:

拦截器是按顺序注册的,类似于express中间件,

您可以访问axios.interceptors.requestaxios.interceptors.response 以访问在拦截器管理器上注册的单元测试功能

例如:

在我的main.js

let axios = require('axios');

axios.interceptors.response.use(
  response => response,
  error => 
    const status = error.response ? error.response.status : null;

    if (status === 401) 
      return makeRequest();
     else 
      return Promise.reject(error);
    
  
);

async function makeRequest() 
  return axios.request('https://randomuser.me/api/');


module.exports = 
  makeRequest
;

在我的main.test.js

let axios = require('axios');

// 
// based on your question, we don't want to test "makeRequest"
// so, I'm loading the file only to register the interceptors
//
require('./main');

let stubAuthError =  response:  status: 401  ;
let stubExceptionError =  response:  status: 500  ;
let stubResponse =  data:  foo: 'bar'  ;

test("interceptor fulfilled", () => 
  let res = axios.interceptors.response.handlers[0].fulfilled(stubResponse);
  expect(res).toEqual(stubResponse);
);

test("interceptor rejected => makeRequest", () => 
  let originalAxiosRequest = axios.request;

  // this fn will be called by "makeRequest"
  axios.request = jest.fn();

  axios.interceptors.response.handlers[0].rejected(stubAuthError);

  expect(axios.request).toHaveBeenCalledTimes(1);

  axios.request = originalAxiosRequest;
);

test("interceptor rejected => exception", async () => 
  await expect(axios.interceptors.response.handlers[0].rejected(stubExceptionError)).rejects.toEqual(stubExceptionError)
);

【讨论】:

以上是关于Axios 中的单元测试拦截器逻辑的主要内容,如果未能解决你的问题,请参考以下文章

单元测试:如何在反应中模拟 axios?

开玩笑的单元测试不会等待 axios 响应

单元测试怎么注入service

如何对使用 Axios(或其他异步更新)的 Vue 组件进行单元测试?

使用 axios、TypeScript 模板和异步函数对 VueJS 进行单元测试

单元测试中的白盒测试设计