如何使用 axios / jest 测试失败的请求

Srd*_*No1 5 javascript unit-testing jestjs axios

我创建了一个非常小的应用程序,如果您传递硬币和数量,它可以计算为某些加密货币支付的总价格。我想测试错误,但我总是收到“收到的承诺已解决而不是被拒绝”。我相信这是因为如果 url 错误 axios 仍然会解决承诺。

我遇到的第二个问题是,我尝试测试 url 是否正确,但我有一个问题,即标头是 url 的一部分,并且我无法弄清楚如何仅测试没有标头的 url 路径。

这些是测试 2 和 3(测试 1 有效)

// getTotalPrice.js
const axios = require("axios");

let symbol = process.argv[2];
let quantity = process.argv[3];

const API = `https://rest.coinapi.io/v1/exchangerate`;
const headers = {headers:{"X-CoinAPI-Key": "MY TOKEN"},};

const getTotalPrice = async (symbol = "BTC", quantity = 1) => {
  try {
  let res = await axios.get(`${API}/${symbol}/USD`, headers);
  let data = res.data;
  return Math.round(data.rate * quantity * 100) / 100;
  } catch(err) {
    console.log(err)
  }
};

getTotalPrice(symbol, quantity);

module.exports = {
  getTotalPrice,
  API
};

// getTotalPrice.test.js

const { get, getError } = require("axios");
const { getTotalPrice } = require("../getTotalPrice");
describe("getTotalPrice", () => {
  afterEach(() => {
    get.mockClear();
  });
  it("fetches data successfully from an api", async () => {
    const res = {
      data: {
        rate: 34000,
      },
    };
    get.mockImplementation(() => Promise.resolve(res));
    await expect(getTotalPrice()).resolves.toEqual(res.data.rate);
  });
  it("throws an error when incorrect data is passed", async () => {
    const errorMessage = "Wrong inputs passed in";

    getError.mockImplementationOnce(() => Promise.reject({}));
    await expect(getTotalPrice()).rejects.toThrowError();
  });
  it("uses correct url", async () => {
    const data = {
      data: {
        rate: 2000,
      },
    };
    get.mockImplementationOnce(() => Promise.resolve(data));

    await getTotalPrice("ETH");
    expect(get).toHaveBeenCalledWith(
      `${API}/ETH/USD`
    );
  });
});

// axios.js (in __mocks__)

module.exports = {
  get: jest.fn(() => Promise.resolve({ data: {} })),
  getError: jest.fn(() => Promise.reject()),
};
Run Code Online (Sandbox Code Playgroud)

回顾一下,测试 1 通过,测试 2 失败,并显示“收到的承诺已解决而不是被拒绝”,测试 3 失败,因为我还获取了标头,而不仅仅是 url。

sli*_*wp2 4

您应该axios.get()使用已解决/拒绝的值进行模拟。由于您使用了该try...catch...语句,因此方法抛出的错误axios.get()将被捕获,并且您没有重新抛出任何错误。因此测试用例 2 的断言将不匹配toThrowError。相反,您可以使用jest.spyOn()将间谍添加到console.log,并断言要使用模拟的调用它Error

\n

这是一个仅使用jest.mock(\'axios\')模拟axios模块而不使用的解决方案__mocks__/axios.js文件的解决方案。

\n

例如

\n

getTotalPrice.js

\n
const axios = require(\'axios\');\n\nlet symbol = process.argv[2];\nlet quantity = process.argv[3];\n\nconst API = `https://rest.coinapi.io/v1/exchangerate`;\nconst headers = { headers: { \'X-CoinAPI-Key\': \'MY TOKEN\' } };\n\nconst getTotalPrice = async (symbol = \'BTC\', quantity = 1) => {\n  try {\n    let res = await axios.get(`${API}/${symbol}/USD`, headers);\n    let data = res.data;\n    return Math.round(data.rate * quantity * 100) / 100;\n  } catch (err) {\n    console.log(err);\n  }\n};\n\nmodule.exports = { getTotalPrice, API };\n
Run Code Online (Sandbox Code Playgroud)\n

getTotalPrice.test.js

\n
const axios = require(\'axios\');\nconst { getTotalPrice, API } = require(\'./getTotalPrice\');\n\njest.mock(\'axios\');\n\ndescribe(\'getTotalPrice\', () => {\n  it(\'fetches data successfully from an api\', async () => {\n    const res = { data: { rate: 34000 } };\n    axios.get.mockResolvedValueOnce(res);\n    await expect(getTotalPrice()).resolves.toEqual(res.data.rate);\n  });\n  it(\'throws an error when incorrect data is passed\', async () => {\n    const logSpy = jest.spyOn(console, \'log\');\n    const err = new Error(\'Wrong inputs passed in\');\n    axios.get.mockRejectedValueOnce(err);\n    await getTotalPrice();\n    expect(logSpy).toBeCalledWith(err);\n  });\n  it(\'uses correct url\', async () => {\n    const res = { data: { rate: 2000 } };\n    axios.get.mockResolvedValueOnce(res);\n    await getTotalPrice(\'ETH\');\n    expect(axios.get).toHaveBeenCalledWith(`${API}/ETH/USD`, { headers: { \'X-CoinAPI-Key\': \'MY TOKEN\' } });\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

测试结果:

\n
 PASS  examples/68200193/getTotalPrice.test.js (7.527 s)\n  getTotalPrice\n    \xe2\x9c\x93 fetches data successfully from an api (3 ms)\n    \xe2\x9c\x93 throws an error when incorrect data is passed (14 ms)\n    \xe2\x9c\x93 uses correct url (1 ms)\n\n  console.log\n    Error: Wrong inputs passed in\n        at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/68200193/getTotalPrice.test.js:14:17\n        at Generator.next (<anonymous>)\n        at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/68200193/getTotalPrice.test.js:8:71\n        at new Promise (<anonymous>)\n        at Object.<anonymous>.__awaiter (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/68200193/getTotalPrice.test.js:4:12)\n        at Object.<anonymous> (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/68200193/getTotalPrice.test.js:12:66)\n        at Object.asyncJestTest (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)\n        at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:45:12\n        at new Promise (<anonymous>)\n        at mapper (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)\n        at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:75:41\n\n      at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)\n          at Generator.throw (<anonymous>)\n\n------------------|---------|----------|---------|---------|-------------------\nFile              | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s \n------------------|---------|----------|---------|---------|-------------------\nAll files         |     100 |      100 |     100 |     100 |                   \n getTotalPrice.js |     100 |      100 |     100 |     100 |                   \n------------------|---------|----------|---------|---------|-------------------\nTest Suites: 1 passed, 1 total\nTests:       3 passed, 3 total\nSnapshots:   0 total\nTime:        8.034 s\n
Run Code Online (Sandbox Code Playgroud)\n