'app.address is not a function' 测试快速 HTTPS 服务器时
'app.address is not a function' when testing an express HTTPS server
我在测试我的 express 应用程序时遇到了问题 运行。所有教程都使用 app.listen
而不是 https.createServer
,我不知道如何正确使用后者的测试框架。代码:
test_node/app.js
var express = require("express");
const app = express();
app.set('port', process.env.SERVER_PORT || 443);
app.get('/', function(req, res){
res.status(200).send('OK');
});
module.exports = {
app: app
}
test_node/server.js
var https = require('https');
var fs = require('fs');
const app = require('./app');
let serverOptions = {
key: fs.readFileSync('./cert/server.key'),
cert: fs.readFileSync('./cert/server.cert')
}
const server = https.createServer(serverOptions, app)
server.listen(app.get('port'), function () {
console.log(`Express HTTPS server listening on port ${app.get('port')}`);
});
async function handleSignal(signal) {
console.log(`Received ${signal}`);
server.close();
process.exit();
}
process.on('SIGINT', handleSignal);
process.on('SIGTERM', handleSignal);
process.on('uncaughtException', handleSignal);
test_node/test/test.js
const request = require('supertest')
describe("Test the root path", () => {
let server;
beforeAll(function () {
server = require('../app');
});
afterAll(function () {
server.close();
});
test("It should respond to the GET method", async () => {
const response = await request(server).get("/");
expect(response.statusCode).toBe(200);
});
});
test_node/package.json
{
"name": "test_node",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js",
"test": "jest"
},
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^26.6.3",
"supertest": "^6.1.3"
},
"dependencies": {
"express": "^4.17.1"
}
}
我用 jest (jest --runInBand test.js
) 测试上面的代码时得到的错误:
TypeError: app.address is not a function
at Test.Object.<anonymous>.Test.serverAddress (C:\code\test_node\node_modules\supertest\lib\test.js:57:18)
at new Test (C:\code\test_node\node_modules\supertest\lib\test.js:38:12)
at Object.get (C:\code\test_node\node_modules\supertest\index.js:27:14)
at Object.<anonymous> (C:\code\test_node\test\test.js:13:48)
at Object.asyncJestTest (C:\code\test_node\node_modules\jest-jasmine2\build\jasmineAsyncInstall.js:106:37)
at C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:45:12
at new Promise (<anonymous>)
at mapper (C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:28:19)
at C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:75:41
这显然是我的代码的精简版。我还在开始时创建了 MongoDB 个连接,但为了简单起见,我删除了它们。理想情况下,我想在测试开始之前使用 async/await 而不是 promises 来创建我的服务器(和 MongoDB 连接)。我还需要在测试结束或失败后关闭这些连接。在您的回答中,您可以放心地假设我是 JS 初学者 :).
附加信息
我在 Windows 10 x64 上使用节点“14.15.4”。网络风暴 IDE.
尝试了以下各种组合:
- 将应用程序和服务器合并到一个文件中(见下文)
- 在单独的函数中创建服务器并导出它
- 使用 mocha/chai 而不是开玩笑
- 正在测试应用程序的精简版
我遇到的错误取决于我尝试的组合:
- 类型错误:app.address 不是函数
- 类型错误:app.get 不是函数
- EADDRINUSE:地址已被使用::::443
- 超时、错误参数等各种其他错误
没有帮助的相关主题(或者我忽略了什么):
- Is it possible to create an Express.js server in my Jest test suite?
- https://blog.campvanilla.com/jest-expressjs-and-the-eaddrinuse-error-bac39356c33a
- https://glebbahmutov.com/blog/how-to-correctly-unit-test-express-server/
- https://rahmanfadhil.com/test-express-with-supertest/
- https://zellwk.com/blog/endpoint-testing/
- https://taylor.fausak.me/2013/02/17/testing-a-node-js-http-server-with-mocha/
- https://www.albertgao.xyz/2017/05/24/how-to-test-expressjs-with-jest-and-supertest/
上下文
我在上面包含了server.js
文件,虽然测试没有使用它,因为我的服务器应用程序在我运行 node server.js
时应该也能正常启动。使用上面的代码它没有启动,我收到以下错误:
events.js:112
throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received an instance of Object
at checkListener (events.js:112:11)
at _addListener (events.js:348:3)
at Server.addListener (events.js:406:10)
at new Server (https.js:71:10)
at Object.createServer (https.js:91:10)
at Object.<anonymous> (C:\code\test_node\server.js:9:22)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14) {
code: 'ERR_INVALID_ARG_TYPE'
}
但是,如果我将所有代码放在同一个 app.js
文件中并且我 运行 node app.js
,那么应用程序可以正常启动,尽管测试会产生相同的错误。
test_node/app.js
var https = require('https');
var fs = require('fs');
var express = require("express");
var server;
const app = express();
app.set('port', process.env.SERVER_PORT || 443);
app.get('/', function(req, res){
res.status(200).send('OK');
});
async function handleSignal(signal) {
console.log(`Received ${signal}`);
server.close();
process.exit();
}
process.on('SIGINT', handleSignal);
process.on('SIGTERM', handleSignal);
process.on('uncaughtException', handleSignal);
let serverOptions = {
key: fs.readFileSync('./cert/server.key'),
cert: fs.readFileSync('./cert/server.cert')
}
server = https.createServer(serverOptions, app).listen(app.get('port'), function () {
console.log(`Express HTTPS server listening on port ${app.get('port')}`);
});
module.exports = {
app: app,
server: server
}
澄清一下,我的问题是如何修复玩笑测试中的错误,而不是我 运行 node server.js
时的错误 - 后者仅用于上下文。
正如@jonrsharpe 在评论中指出的那样,我假设使用 module.exports
我导出了应用程序本身,但实际上我导出了一个包含该应用程序的对象。因此,为了修复测试错误,我不得不简单地写在我的 test.js:
server = require('../app').app;
而不是 server = require('../app');
。同样,在 server.js 中我不得不写:
const app = require('./app').app;
这修复了我在问题中提到的两个错误 (TypeError: app.address is not a function
)。
感谢@jonrsharpe 帮助我找到解决方案!
我在测试我的 express 应用程序时遇到了问题 运行。所有教程都使用 app.listen
而不是 https.createServer
,我不知道如何正确使用后者的测试框架。代码:
test_node/app.js
var express = require("express");
const app = express();
app.set('port', process.env.SERVER_PORT || 443);
app.get('/', function(req, res){
res.status(200).send('OK');
});
module.exports = {
app: app
}
test_node/server.js
var https = require('https');
var fs = require('fs');
const app = require('./app');
let serverOptions = {
key: fs.readFileSync('./cert/server.key'),
cert: fs.readFileSync('./cert/server.cert')
}
const server = https.createServer(serverOptions, app)
server.listen(app.get('port'), function () {
console.log(`Express HTTPS server listening on port ${app.get('port')}`);
});
async function handleSignal(signal) {
console.log(`Received ${signal}`);
server.close();
process.exit();
}
process.on('SIGINT', handleSignal);
process.on('SIGTERM', handleSignal);
process.on('uncaughtException', handleSignal);
test_node/test/test.js
const request = require('supertest')
describe("Test the root path", () => {
let server;
beforeAll(function () {
server = require('../app');
});
afterAll(function () {
server.close();
});
test("It should respond to the GET method", async () => {
const response = await request(server).get("/");
expect(response.statusCode).toBe(200);
});
});
test_node/package.json
{
"name": "test_node",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js",
"test": "jest"
},
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^26.6.3",
"supertest": "^6.1.3"
},
"dependencies": {
"express": "^4.17.1"
}
}
我用 jest (jest --runInBand test.js
) 测试上面的代码时得到的错误:
TypeError: app.address is not a function
at Test.Object.<anonymous>.Test.serverAddress (C:\code\test_node\node_modules\supertest\lib\test.js:57:18)
at new Test (C:\code\test_node\node_modules\supertest\lib\test.js:38:12)
at Object.get (C:\code\test_node\node_modules\supertest\index.js:27:14)
at Object.<anonymous> (C:\code\test_node\test\test.js:13:48)
at Object.asyncJestTest (C:\code\test_node\node_modules\jest-jasmine2\build\jasmineAsyncInstall.js:106:37)
at C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:45:12
at new Promise (<anonymous>)
at mapper (C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:28:19)
at C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:75:41
这显然是我的代码的精简版。我还在开始时创建了 MongoDB 个连接,但为了简单起见,我删除了它们。理想情况下,我想在测试开始之前使用 async/await 而不是 promises 来创建我的服务器(和 MongoDB 连接)。我还需要在测试结束或失败后关闭这些连接。在您的回答中,您可以放心地假设我是 JS 初学者 :).
附加信息
我在 Windows 10 x64 上使用节点“14.15.4”。网络风暴 IDE.
尝试了以下各种组合:
- 将应用程序和服务器合并到一个文件中(见下文)
- 在单独的函数中创建服务器并导出它
- 使用 mocha/chai 而不是开玩笑
- 正在测试应用程序的精简版
我遇到的错误取决于我尝试的组合:
- 类型错误:app.address 不是函数
- 类型错误:app.get 不是函数
- EADDRINUSE:地址已被使用::::443
- 超时、错误参数等各种其他错误
没有帮助的相关主题(或者我忽略了什么):
- Is it possible to create an Express.js server in my Jest test suite?
- https://blog.campvanilla.com/jest-expressjs-and-the-eaddrinuse-error-bac39356c33a
- https://glebbahmutov.com/blog/how-to-correctly-unit-test-express-server/
- https://rahmanfadhil.com/test-express-with-supertest/
- https://zellwk.com/blog/endpoint-testing/
- https://taylor.fausak.me/2013/02/17/testing-a-node-js-http-server-with-mocha/
- https://www.albertgao.xyz/2017/05/24/how-to-test-expressjs-with-jest-and-supertest/
上下文
我在上面包含了server.js
文件,虽然测试没有使用它,因为我的服务器应用程序在我运行 node server.js
时应该也能正常启动。使用上面的代码它没有启动,我收到以下错误:
events.js:112
throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received an instance of Object
at checkListener (events.js:112:11)
at _addListener (events.js:348:3)
at Server.addListener (events.js:406:10)
at new Server (https.js:71:10)
at Object.createServer (https.js:91:10)
at Object.<anonymous> (C:\code\test_node\server.js:9:22)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14) {
code: 'ERR_INVALID_ARG_TYPE'
}
但是,如果我将所有代码放在同一个 app.js
文件中并且我 运行 node app.js
,那么应用程序可以正常启动,尽管测试会产生相同的错误。
test_node/app.js
var https = require('https');
var fs = require('fs');
var express = require("express");
var server;
const app = express();
app.set('port', process.env.SERVER_PORT || 443);
app.get('/', function(req, res){
res.status(200).send('OK');
});
async function handleSignal(signal) {
console.log(`Received ${signal}`);
server.close();
process.exit();
}
process.on('SIGINT', handleSignal);
process.on('SIGTERM', handleSignal);
process.on('uncaughtException', handleSignal);
let serverOptions = {
key: fs.readFileSync('./cert/server.key'),
cert: fs.readFileSync('./cert/server.cert')
}
server = https.createServer(serverOptions, app).listen(app.get('port'), function () {
console.log(`Express HTTPS server listening on port ${app.get('port')}`);
});
module.exports = {
app: app,
server: server
}
澄清一下,我的问题是如何修复玩笑测试中的错误,而不是我 运行 node server.js
时的错误 - 后者仅用于上下文。
正如@jonrsharpe 在评论中指出的那样,我假设使用 module.exports
我导出了应用程序本身,但实际上我导出了一个包含该应用程序的对象。因此,为了修复测试错误,我不得不简单地写在我的 test.js:
server = require('../app').app;
而不是 server = require('../app');
。同样,在 server.js 中我不得不写:
const app = require('./app').app;
这修复了我在问题中提到的两个错误 (TypeError: app.address is not a function
)。
感谢@jonrsharpe 帮助我找到解决方案!