[英]What's the best way to test express.js API
我是使用 JavaScript 进行 API 测试的新手。 我找到了许多测试 REST API 的解决方案,但不确定什么是最好的。 我在后端和测试中使用 express.js 开玩笑。
我已经看到我可以开玩笑地测试,通过模拟函数或者我也可以直接模拟 API。
我有一个存储对象的 data.js:
let data = [
{
id: 0,
name: "empty shopppinglist",
location: "",
targetDate: "",
priority: "",
isFinished: false,
items: ["vodka"
]
}
]
module.exports = data
然后在后端文件夹中,我有这个来提供端点并读取/返回文件:
function getData(){
let shoppingLists = data
return shoppingLists
}
module.exports.getData = getData
let shoppingLists = data
app.get('/api/shoppingLists', (req, res) => {
const listsWithoutItems = getData().map(({ items, ...rest }) => rest)
res.status(200).send(listsWithoutItems)
})
我在这里也不确定,如果我可以将 app.get 调用移动到一个函数。
在我的测试中,我想测试 API 的行为,因此如果数据无效,我将收到错误 500 等。为此,我已经尝试过此测试:
describe('Get Endpoint for all Lists', () => {
it('should return 2 lists', async () => {
myapp.getData = jest.fn(() => [
{
"id": 0,
"name": "filled shopping list",
"location": "lidl",
"targetDate": "22.03.1986",
"priority": "1",
"isFinished": false,
"items": ["vanille"
]
}
])
const res = await request(myapp)
.get('/api/shoppingLists')
expect(res.statusCode).toEqual(200)
expect(res.body).toHaveProperty('2')
})
})
不幸的是,我总是从 data.js 获取原始条目,而不是模拟结果。 通过搜索文档,我还看到,我可以模拟定义我的 API 的整个 app.js。 但现在我不确定什么是更好的方法。
将getData
模拟为myapp.getData
是不可能的。 module.exports.getData = getData
不能很好地用于测试,因为它允许模拟getData
仅当它在任何地方用作exports.getData()
而不是getData()
,这是不切实际的。
data
需要在它定义的模块中进行模拟。 然后,每个测试都应该重新导入依赖于它的所有模块,以便受到模拟的影响。 jest.isolateModules
或jest.resetModules
可以与require
结合使用以提供特定于测试的模块模拟。
beforeEach(() => {
jest.resetModules();
});
it('should return 2 lists', async () => {
jest.mock('.../data', () => [...]);
const myapp = require('.../app');
const res = await request(myapp)
...
});
我想我已经达到了我想要的设置:
await
,没有无限深度嵌套的回调在此示例中未显示,当使用NODE_ENV=test
时,您可能希望通过使用每个测试唯一的临时内存 SQLite 数据库运行应用程序来完成任务。 真正的生产服务器会在 PostgreSQL 之类的东西上运行,并且会使用像 sequelize 这样的 ORM,以便相同的代码可以在两者上运行。 或者,您可以设置一次创建数据库并在每次测试之前截断所有表。
应用程序.js
#!/usr/bin/env node
const express = require('express')
async function start(port, cb) {
const app = express()
app.get('/', (req, res) => {
res.send(`asdf`)
})
app.get('/qwer', (req, res) => {
res.send(`zxcv`)
})
return new Promise((resolve, reject) => {
const server = app.listen(port, async function() {
try {
cb && await cb(server)
} catch (e) {
reject(e)
this.close()
throw e
}
})
server.on('close', resolve)
})
}
if (require.main === module) {
start(3000, server => {
console.log('Listening on: http://localhost:' + server.address().port)
})
}
module.exports = { start }
测试.js
const assert = require('assert');
const http = require('http')
const app = require('./app')
function testApp(cb) {
return app.start(0, async (server) => {
await cb(server)
server.close()
})
}
// https://stackoverflow.com/questions/6048504/synchronous-request-in-node-js/53338670#53338670
function sendJsonHttp(opts) {
return new Promise((resolve, reject) => {
const body = JSON.stringify(opts.body)
const options = {
hostname: 'localhost',
port: opts.server.address().port,
path: opts.path,
method: opts.method,
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body),
}
}
const req = http.request(options, res => {
res.on('data', data => {
resolve([res, data.toString()])
})
})
req.write(body)
req.end()
})
}
it('test root', () => {
// When an async function is used, Mocha waits for the promise to resolve
// before deciding pass/fail.
return testApp(async (server) => {
let res, data
// First request, normally a POST that changes state.
;[res, data] = await sendJsonHttp({
server,
method: 'GET',
path: '/',
body: {},
})
assert.strictEqual(res.statusCode, 200)
assert.strictEqual(data, 'asdf')
// Second request, normally a GET to check that POST.
;[res, data] = await sendJsonHttp({
server,
method: 'GET',
path: '/',
body: {},
})
assert.strictEqual(res.statusCode, 200)
assert.strictEqual(data, 'asdf')
})
})
it('test /qwer', () => {
return testApp(async (server) => {
let res, data
;[res, data] = await sendJsonHttp({
server,
method: 'GET',
path: '/qwer',
body: {},
})
assert.strictEqual(res.statusCode, 200)
assert.strictEqual(data, 'zxcv')
})
})
包.json
{
"name": "tmp",
"version": "1.0.0",
"dependencies": {
"express": "4.17.1"
},
"devDependencies": {
"mocha": "6.2.2"
},
"scripts": {
"test": "mocha test test.js"
}
}
有了这个,运行:
npm install
./app
根据需要正常运行服务器。 并运行:
npm test
使测试按需要工作。 值得注意的是,如果您将任何断言破解为错误的值,它们将抛出,服务器关闭而不挂起,最后失败的测试显示为失败。
异步 http 请求也在: Node.js 中的同步请求
在 Node.js 14.17.0、Ubuntu 21.10 上测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.