如何使用 Frisby 和 Jest 模拟函数以 return 自定义响应?
How to mock a function using Frisby and Jest to return custom response?
我正在尝试使用 Frisby 和 Jest 模拟一个函数。
以下是有关我的代码的一些详细信息:
依赖项
公理:“^0.26.0”,
dotenv: "^16.0.0",
表示:“^4.17.2”
devDependencies
飞盘:“^2.1.3”,
开玩笑:“^27.5.1”
当我使用 Jest 进行模拟时,来自 API 的正确响应是 returned,但我不想要它。我想要 return 一个像这样的假结果:{ a: 'b' }
.
如何解决?
我有以下代码:
// (API Fetch file) backend/api/fetchBtcCurrency.js
const axios = require('axios');
const URL = 'https://api.coindesk.com/v1/bpi/currentprice/BTC.json';
const getCurrency = async () => {
const response = await axios.get(URL);
return response.data;
};
module.exports = {
getCurrency,
};
// (Model using fetch file) backend/model/cryptoModel.js
const fetchBtcCurrency = require('../api/fetchBtcCurrency');
const getBtcCurrency = async () => {
const responseFromApi = await fetchBtcCurrency.getCurrency();
return responseFromApi;
};
module.exports = {
getBtcCurrency,
};
// (My test file) /backend/__tests__/cryptoBtc.test.js
require("dotenv").config();
const frisby = require("frisby");
const URL = "http://localhost:4000/";
describe("Testing GET /api/crypto/btc", () => {
beforeEach(() => {
jest.mock('../api/fetchBtcCurrency');
});
it('Verify if returns correct response with status code 200', async () => {
const fetchBtcCurrency = require('../api/fetchBtcCurrency').getCurrency;
fetchBtcCurrency.mockImplementation(() => (JSON.stringify({ a: 'b'})));
const defaultExport = await fetchBtcCurrency();
expect(defaultExport).toBe(JSON.stringify({ a: 'b'})); // This assert works
await frisby
.get(`${URL}api/crypto/btc`)
.expect('status', 200)
.expect('json', { a: 'b'}); // Integration test with Frisby does not work correctly.
});
});
Response[
{
I hid the lines to save screen space.
}
->>>>>>> does not contain provided JSON [ {"a":"b"} ]
];
这是一个经典的丢失引用问题。
由于您使用的是 Frisby,通过查看您的测试,您似乎是在并行启动服务器,对吗?您首先使用 npm start
启动服务器,然后 运行 使用 npm test
.
进行测试
问题在于:当您的测试开始时,您的服务器已经 运行ning。因为你用真正的 fetchBtcCurrency.getCurrency
启动了你的服务器,jest 从这一点开始就不能做任何事情了。您的服务器将继续指向真实模块,而不是模拟模块。
测试中对导入的断言之所以有效,是因为该导入是在模拟替换真实文件之后进行的。
您没有共享 app
或 server
文件,但是如果您在同一个模块上创建服务器 并监听 ,那么那些是“挂在全局”(即:从脚本主体调用,而不是函数的一部分),你必须将它们分开。您将需要一个创建服务器的文件(向其附加任何 route/middleware/etc),并且您将需要一个单独的文件 just 来导入第一个文件并开始收听。
例如:
app.js
const express = require('express');
const { getCurrency } = require('./fetchBtcCurrency');
const app = express()
app.get('/api/crypto/btc', async (req, res) => {
const currency = await getCurrency();
res.status(200).json(currency);
});
module.exports = { app }
server.js
const { app } = require('./app');
app.listen(4000, () => {
console.log('server is up on port 4000');
});
然后,在您的 start 脚本中,您 运行 server
文件。但是,在您的测试中,您导入了 app
文件。 您不能并行启动服务器。 您将作为测试的一部分启动和停止它 setup/teardown。
这将使 jest 有机会在服务器开始监听之前用模拟模块替换真实模块(此时它失去对它的控制)
这样,您的测试可以是:
cryptoBtc.test.js
require("dotenv").config();
const frisby = require("frisby");
const URL = "http://localhost:4000/";
const fetchBtcCurrency = require('./fetchBtcCurrency');
const { app } = require('./app');
jest.mock('./fetchBtcCurrency')
describe("Testing GET /api/crypto/btc", () => {
let server;
beforeAll((done) => {
server = app.listen(4000, () => {
done();
});
});
afterAll(() => {
server.close();
});
it('Verify if returns correct response with status code 200', async () => {
fetchBtcCurrency.getCurrency.mockImplementation(() => ({ a: 'b' }));
await frisby
.get(`${URL}api/crypto/btc`)
.expect('status', 200)
.expect('json', { a: 'b'});
});
});
请注意导入顺序无关紧要。你可以在真正的导入下面做“模拟”。 Jest 足够聪明,知道模拟应该放在第一位。
我正在尝试使用 Frisby 和 Jest 模拟一个函数。 以下是有关我的代码的一些详细信息:
依赖项 公理:“^0.26.0”, dotenv: "^16.0.0", 表示:“^4.17.2”
devDependencies 飞盘:“^2.1.3”, 开玩笑:“^27.5.1”
当我使用 Jest 进行模拟时,来自 API 的正确响应是 returned,但我不想要它。我想要 return 一个像这样的假结果:{ a: 'b' }
.
如何解决?
我有以下代码:
// (API Fetch file) backend/api/fetchBtcCurrency.js
const axios = require('axios');
const URL = 'https://api.coindesk.com/v1/bpi/currentprice/BTC.json';
const getCurrency = async () => {
const response = await axios.get(URL);
return response.data;
};
module.exports = {
getCurrency,
};
// (Model using fetch file) backend/model/cryptoModel.js
const fetchBtcCurrency = require('../api/fetchBtcCurrency');
const getBtcCurrency = async () => {
const responseFromApi = await fetchBtcCurrency.getCurrency();
return responseFromApi;
};
module.exports = {
getBtcCurrency,
};
// (My test file) /backend/__tests__/cryptoBtc.test.js
require("dotenv").config();
const frisby = require("frisby");
const URL = "http://localhost:4000/";
describe("Testing GET /api/crypto/btc", () => {
beforeEach(() => {
jest.mock('../api/fetchBtcCurrency');
});
it('Verify if returns correct response with status code 200', async () => {
const fetchBtcCurrency = require('../api/fetchBtcCurrency').getCurrency;
fetchBtcCurrency.mockImplementation(() => (JSON.stringify({ a: 'b'})));
const defaultExport = await fetchBtcCurrency();
expect(defaultExport).toBe(JSON.stringify({ a: 'b'})); // This assert works
await frisby
.get(`${URL}api/crypto/btc`)
.expect('status', 200)
.expect('json', { a: 'b'}); // Integration test with Frisby does not work correctly.
});
});
Response[
{
I hid the lines to save screen space.
}
->>>>>>> does not contain provided JSON [ {"a":"b"} ]
];
这是一个经典的丢失引用问题。
由于您使用的是 Frisby,通过查看您的测试,您似乎是在并行启动服务器,对吗?您首先使用 npm start
启动服务器,然后 运行 使用 npm test
.
问题在于:当您的测试开始时,您的服务器已经 运行ning。因为你用真正的 fetchBtcCurrency.getCurrency
启动了你的服务器,jest 从这一点开始就不能做任何事情了。您的服务器将继续指向真实模块,而不是模拟模块。
测试中对导入的断言之所以有效,是因为该导入是在模拟替换真实文件之后进行的。
您没有共享 app
或 server
文件,但是如果您在同一个模块上创建服务器 并监听 ,那么那些是“挂在全局”(即:从脚本主体调用,而不是函数的一部分),你必须将它们分开。您将需要一个创建服务器的文件(向其附加任何 route/middleware/etc),并且您将需要一个单独的文件 just 来导入第一个文件并开始收听。
例如:
app.js
const express = require('express');
const { getCurrency } = require('./fetchBtcCurrency');
const app = express()
app.get('/api/crypto/btc', async (req, res) => {
const currency = await getCurrency();
res.status(200).json(currency);
});
module.exports = { app }
server.js
const { app } = require('./app');
app.listen(4000, () => {
console.log('server is up on port 4000');
});
然后,在您的 start 脚本中,您 运行 server
文件。但是,在您的测试中,您导入了 app
文件。 您不能并行启动服务器。 您将作为测试的一部分启动和停止它 setup/teardown。
这将使 jest 有机会在服务器开始监听之前用模拟模块替换真实模块(此时它失去对它的控制)
这样,您的测试可以是:
cryptoBtc.test.js
require("dotenv").config();
const frisby = require("frisby");
const URL = "http://localhost:4000/";
const fetchBtcCurrency = require('./fetchBtcCurrency');
const { app } = require('./app');
jest.mock('./fetchBtcCurrency')
describe("Testing GET /api/crypto/btc", () => {
let server;
beforeAll((done) => {
server = app.listen(4000, () => {
done();
});
});
afterAll(() => {
server.close();
});
it('Verify if returns correct response with status code 200', async () => {
fetchBtcCurrency.getCurrency.mockImplementation(() => ({ a: 'b' }));
await frisby
.get(`${URL}api/crypto/btc`)
.expect('status', 200)
.expect('json', { a: 'b'});
});
});
请注意导入顺序无关紧要。你可以在真正的导入下面做“模拟”。 Jest 足够聪明,知道模拟应该放在第一位。