axios-mock-adapter vs fetch-mock vs msw vs nock
HTTP Mocking Libraries
axios-mock-adapterfetch-mockmswnock类似的npm包:

HTTP Mocking Libraries

HTTP Mocking Libraries are essential tools in web development that allow developers to simulate HTTP requests and responses. These libraries are particularly useful for testing and development purposes, enabling developers to create reliable tests without relying on actual API endpoints. By mocking HTTP requests, developers can isolate their code from external dependencies, ensuring that tests run consistently and quickly. Each library offers unique features and approaches to mocking, catering to different use cases and preferences in the development workflow.

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
axios-mock-adapter03,55167.9 kB961 年前MIT
fetch-mock01,309157 kB95 个月前MIT
msw017,7634.92 MB425 天前MIT
nock013,090185 kB881 个月前MIT

功能对比: axios-mock-adapter vs fetch-mock vs msw vs nock

集成方式

  • axios-mock-adapter:

    axios-mock-adapter 是专为 Axios 设计的,允许开发者通过简单的 API 来模拟 Axios 的请求和响应。它的集成方式非常直接,能够轻松地与现有的 Axios 实例一起使用。

  • fetch-mock:

    fetch-mock 提供了灵活的 API,可以与 Fetch API 无缝集成。它允许开发者在测试中轻松地定义模拟的请求和响应,并支持多种配置选项。

  • msw:

    msw 利用 Service Worker 技术,能够在浏览器中拦截网络请求。它与前端框架(如 React、Vue 和 Angular)兼容,提供了更真实的测试环境。

  • nock:

    nock 是一个专为 Node.js 设计的库,能够拦截 HTTP 请求并提供模拟响应。它允许开发者在测试中验证请求的参数和响应,适合于后端服务的测试。

功能特性

  • axios-mock-adapter:

    axios-mock-adapter 提供了简单的 API 来设置模拟响应,包括延迟、错误处理和请求匹配。它支持对请求的 URL、方法和数据进行精确匹配。

  • fetch-mock:

    fetch-mock 提供了丰富的功能,包括请求拦截、响应延迟、随机响应、条件响应等。它支持对请求的 URL 和方法进行灵活匹配,并允许使用正则表达式。

  • msw:

    msw 提供了强大的功能,能够在真实的请求和响应之间进行拦截,支持 REST 和 GraphQL API。它允许开发者定义请求处理程序,并在测试中轻松模拟复杂的网络交互。

  • nock:

    nock 允许开发者定义请求的 URL、方法和响应,支持验证请求的参数。它还提供了链式调用的方式来设置多个请求的模拟,非常灵活。

测试环境

  • axios-mock-adapter:

    axios-mock-adapter 适用于前端开发,特别是当使用 Axios 作为 HTTP 客户端时。它能够在测试中快速设置和清理模拟状态。

  • fetch-mock:

    fetch-mock 适用于使用 Fetch API 的前端项目,能够轻松地模拟 HTTP 请求,适合于单元测试和集成测试。

  • msw:

    msw 提供了一个接近真实环境的测试体验,适合于现代前端框架的开发。它能够在浏览器中模拟请求,适合于 UI 测试和集成测试。

  • nock:

    nock 主要用于 Node.js 环境,适合于后端服务的测试。它能够在集成测试中模拟 HTTP 请求,确保后端逻辑的正确性。

学习曲线

  • axios-mock-adapter:

    axios-mock-adapter 的学习曲线相对较低,特别是对于已经熟悉 Axios 的开发者。它提供了简单的 API,易于上手。

  • fetch-mock:

    fetch-mock 的学习曲线也较低,特别是对于使用 Fetch API 的开发者。它的文档清晰,易于理解和使用。

  • msw:

    msw 的学习曲线稍高,因为它引入了 Service Worker 的概念,但一旦掌握,提供的功能非常强大,适合复杂的测试场景。

  • nock:

    nock 的学习曲线相对较低,特别是对于熟悉 Node.js 的开发者。它的 API 简单明了,易于使用。

社区支持

  • axios-mock-adapter:

    axios-mock-adapter 拥有活跃的社区支持,文档齐全,提供了丰富的示例和使用案例。

  • fetch-mock:

    fetch-mock 也有良好的社区支持,提供了详细的文档和示例,帮助开发者快速上手。

  • msw:

    msw 拥有强大的社区支持,文档丰富,提供了大量的示例和最佳实践,适合现代开发者使用。

  • nock:

    nock 拥有广泛的社区支持,文档清晰,适合于 Node.js 开发者,提供了多种使用案例。

如何选择: axios-mock-adapter vs fetch-mock vs msw vs nock

  • axios-mock-adapter:

    选择 axios-mock-adapter 如果你已经在项目中使用 Axios 作为 HTTP 客户端,并希望轻松地模拟 Axios 请求和响应。它与 Axios 紧密集成,提供简单的 API 来设置和管理模拟。

  • fetch-mock:

    选择 fetch-mock 如果你的项目使用 Fetch API,并且你需要一个灵活的解决方案来模拟 HTTP 请求。fetch-mock 提供了丰富的功能,包括请求拦截、响应延迟和自定义响应。

  • msw:

    选择 msw (Mock Service Worker) 如果你希望在浏览器中模拟网络请求,利用 Service Worker 的能力。msw 允许你在真实的请求和响应之间进行拦截,提供更接近真实环境的测试体验,适合于现代前端框架。

  • nock:

    选择 nock 如果你需要在 Node.js 环境中模拟 HTTP 请求。nock 允许你拦截和模拟 HTTP 请求,适合于后端测试和集成测试,能够轻松地验证请求的参数和响应。

axios-mock-adapter的README

axios-mock-adapter

Axios adapter that allows to easily mock requests

Installation

Using npm:

$ npm install axios-mock-adapter --save-dev

It's also available as a UMD build:

axios-mock-adapter works on Node as well as in a browser, it works with axios v0.17.0 and above.

Example

Mocking a GET request

const axios = require("axios");
const AxiosMockAdapter = require("axios-mock-adapter");

// This sets the mock adapter on the default instance
const mock = new AxiosMockAdapter(axios);

// Mock any GET request to /users
// arguments for reply are (status, data, headers)
mock.onGet("/users").reply(200, {
  users: [{ id: 1, name: "John Smith" }],
});

axios.get("/users").then(function (response) {
  console.log(response.data);
});

Mocking a GET request with specific parameters

const axios = require("axios");
const AxiosMockAdapter = require("axios-mock-adapter");

// This sets the mock adapter on the default instance
const mock = new AxiosMockAdapter(axios);

// Mock GET request to /users when param `searchText` is 'John'
// arguments for reply are (status, data, headers)
mock.onGet("/users", { params: { searchText: "John" } }).reply(200, {
  users: [{ id: 1, name: "John Smith" }],
});

axios
  .get("/users", { params: { searchText: "John" } })
  .then(function (response) {
    console.log(response.data);
  });

When using params, you must match all key/value pairs passed to that option.

To add a delay to responses, specify a delay amount (in milliseconds) when instantiating the adapter

// All requests using this instance will have a 2 seconds delay:
const mock = new AxiosMockAdapter(axiosInstance, { delayResponse: 2000 });

You can restore the original adapter (which will remove the mocking behavior)

mock.restore();

You can also reset the registered mock handlers with resetHandlers

mock.resetHandlers();

You can reset both registered mock handlers and history items with reset

mock.reset();

reset is different from restore in that restore removes the mocking from the axios instance completely, whereas reset only removes all mock handlers that were added with onGet, onPost, etc. but leaves the mocking in place.

Mock a low level network error

// Returns a failed promise with Error('Network Error');
mock.onGet("/users").networkError();

// networkErrorOnce can be used to mock a network error only once
mock.onGet("/users").networkErrorOnce();

Mock a network timeout

// Returns a failed promise with Error with code set to 'ECONNABORTED'
mock.onGet("/users").timeout();

// timeoutOnce can be used to mock a timeout only once
mock.onGet("/users").timeoutOnce();

Passing a function to reply

mock.onGet("/users").reply(function (config) {
  // `config` is the axios config and contains things like the url

  // return an array in the form of [status, data, headers]
  return [
    200,
    {
      users: [{ id: 1, name: "John Smith" }],
    },
  ];
});

Passing a function to reply that returns an axios request, essentially mocking a redirect

mock.onPost("/foo").reply(function (config) {
  return axios.get("/bar");
});

Using a regex

mock.onGet(/\/users\/\d+/).reply(function (config) {
  // the actual id can be grabbed from config.url

  return [200, {}];
});

Using variables in regex

const usersUri = "/users";
const url = new RegExp(`${usersUri}/*`);

mock.onGet(url).reply(200, users);

Specify no path to match by verb alone

// Reject all POST requests with HTTP 500
mock.onPost().reply(500);

Chaining is also supported

mock.onGet("/users").reply(200, users).onGet("/posts").reply(200, posts);

.replyOnce() can be used to let the mock only reply once

mock
  .onGet("/users")
  .replyOnce(200, users) // After the first request to /users, this handler is removed
  .onGet("/users")
  .replyOnce(500); // The second request to /users will have status code 500
// Any following request would return a 404 since there are
// no matching handlers left

Mocking any request to a given url

// mocks GET, POST, ... requests to /foo
mock.onAny("/foo").reply(200);

.onAny can be useful when you want to test for a specific order of requests

// Expected order of requests:
const responses = [
  ["GET", "/foo", 200, { foo: "bar" }],
  ["POST", "/bar", 200],
  ["PUT", "/baz", 200],
];

// Match ALL requests
mock.onAny().reply((config) => {
  const [method, url, ...response] = responses.shift();
  if (config.url === url && config.method.toUpperCase() === method)
    return response;
  // Unexpected request, error out
  return [500, {}];
});

Requests that do not map to a mock handler are rejected with a HTTP 404 response. Since handlers are matched in order, a final onAny() can be used to change the default behaviour

// Mock GET requests to /foo, reject all others with HTTP 500
mock.onGet("/foo").reply(200).onAny().reply(500);

Mocking a request with a specific request body/data

mock.onPut("/product", { id: 4, name: "foo" }).reply(204);

Using an asymmetric matcher, for example Jest matchers

mock
  .onPost(
    "/product",
    { id: 1 },
    {
      headers: expect.objectContaining({
        Authorization: expect.stringMatching(/^Basic /),
      })
    }
  )
  .reply(204);

Using a custom asymmetric matcher (any object that has a asymmetricMatch property)

mock
  .onPost("/product", {
    asymmetricMatch: function (actual) {
      return ["computer", "phone"].includes(actual["type"]);
    },
  })
  .reply(204);

.passThrough() forwards the matched request over network

// Mock POST requests to /api with HTTP 201, but forward
// GET requests to server
mock
  .onPost(/^\/api/)
  .reply(201)
  .onGet(/^\/api/)
  .passThrough();

Recall that the order of handlers is significant

// Mock specific requests, but let unmatched ones through
mock
  .onGet("/foo")
  .reply(200)
  .onPut("/bar", { xyz: "abc" })
  .reply(204)
  .onAny()
  .passThrough();

Note that passThrough requests are not subject to delaying by delayResponse.

If you set onNoMatch option to passthrough all requests would be forwarded over network by default

// Mock all requests to /foo with HTTP 200, but forward
// any others requests to server
const mock = new AxiosMockAdapter(axiosInstance, { onNoMatch: "passthrough" });

mock.onAny("/foo").reply(200);

Using onNoMatch option with throwException to throw an exception when a request is made without match any handler. It's helpful to debug your test mocks.

const mock = new AxiosMockAdapter(axiosInstance, { onNoMatch: "throwException" });

mock.onAny("/foo").reply(200);

axios.get("/unexistent-path");

// Exception message on console:
//
// Could not find mock for: 
// {
//   "method": "get",
//   "url": "http://localhost/unexistent-path"
// }

As of 1.7.0, reply function may return a Promise:

mock.onGet("/product").reply(function (config) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (Math.random() > 0.1) {
        resolve([200, { id: 4, name: "foo" }]);
      } else {
        // reject() reason will be passed as-is.
        // Use HTTP error status code to simulate server failure.
        resolve([500, { success: false }]);
      }
    }, 1000);
  });
});

Composing from multiple sources with Promises:

const normalAxios = axios.create();
const mockAxios = axios.create();
const mock = new AxiosMockAdapter(mockAxios);

mock
  .onGet("/orders")
  .reply(() =>
    Promise.all([
      normalAxios.get("/api/v1/orders").then((resp) => resp.data),
      normalAxios.get("/api/v2/orders").then((resp) => resp.data),
      { id: "-1", content: "extra row 1" },
      { id: "-2", content: "extra row 2" },
    ]).then((sources) => [
      200,
      sources.reduce((agg, source) => agg.concat(source)),
    ])
  );

History

The history property allows you to enumerate existing axios request objects. The property is an object of verb keys referencing arrays of request objects.

This is useful for testing.

describe("Feature", () => {
  it("requests an endpoint", (done) => {
    const mock = new AxiosMockAdapter(axios);
    mock.onPost("/endpoint").replyOnce(200);

    feature
      .request()
      .then(() => {
        expect(mock.history.post.length).toBe(1);
        expect(mock.history.post[0].data).toBe(JSON.stringify({ foo: "bar" }));
      })
      .then(done)
      .catch(done.fail);
  });
});

You can clear the history with resetHistory

mock.resetHistory();