我是Nodejs的新手,我正在udemy上学习Nodejs课程,我在多次重新运行集成测试时遇到了一些listen EADDRINUSE: address already in use :::4000
的问题。第一次成功了,但是后来我在下面的行中得到了上面提到的错误
const server = app.listen(port, () => {winston.info(`Listening on port ${port}`)});
我正在粘贴我的index.js和两个测试文件,如果有人能指出我,这将对我有很大的帮助。
index.js
const Joi = require("@hapi/joi");
Joi.objectId = require("joi-objectid")(Joi);
const winston = require("winston");
const express = require("express");
const app = express();
require("./startup/logging")();
require("./startup/config")();
require("./startup/dbconnectivity")();
require("./startup/routes")(app);
const port = process.env.port || 4000;
const server = app.listen(port, () => {winston.info(`Listening on port ${port}`)});
// exporting server object to be used in integration tests.
module.exports = server;
**Integration test file for Genre**
const request = require("supertest");
let server;
const {Genere} = require("../../models/genere");
const {User} = require("../../models/user");
describe("/api/genere", () => {
beforeEach(() => {
console.log("Before each Genre");
server = require("../../index");
});
afterEach(async () => {
console.log("After each Genre");
await Genere.deleteMany({});
await server.close();
});
describe("/GET", () => {
it("should return list of generes", async() => {
await Genere.insertMany([
{name: "genre1"},
{name: "genre2"},
{name: "genre3"}
]);
const res = await request(server).get("/api/geners");
expect(res.status).toBe(200);
console.log("response body is : " + res.body);
expect(res.body.length).toBe(3);
expect(res.body.map(g => g.name)).toContain("genre1");
});
});
describe("/GET/:id", () => {
it("should return genre with id", async() => {
const genre = new Genere({name: "genre1"});
await genre.save();
const res = await request(server).get("/api/geners/"+ genre.id);
expect(res.status).toBe(200);
expect(res.body.name).toBe("genre1");
});
it("should return error with invalid id", async() => {
const genre = new Genere({name: "genre1"});
await genre.save();
const res = await request(server).get("/api/geners/1");
expect(res.status).toBe(404);
expect(res.text).toMatch(/Invalid/);
});
});
describe("/POST", () => {
it("should return 401 if not authorized", async() => {
const genere = new Genere({name: "genere1"});
const res = await request(server).post("/api/geners").send(genere);
expect(res.status).toBe(401);
});
it("should return 400 if the name is less than 4 chars", async() => {
const res = await createRequestWithGenre({name: "g1"});
expect(res.status).toBe(400);
});
it("should return 400 if the name is greater than 25 chars", async() => {
const genreName = Array(26).fill("a").join("");
const res = await createRequestWithGenre({name: genreName})
expect(res.status).toBe(400);
});
it("should return 201 with gener object if proper object is sent", async() => {
const res = await createRequestWithGenre({name: "genre1"})
expect(res.status).toBe(201);
expect(res.body).toHaveProperty("_id");
expect(res.body).toHaveProperty("name", "genre1");
const genre = await Genere.find({ name: "genre1"});
expect(genre).not.toBe(null);
});
async function createRequestWithGenre(genre) {
const token = new User().generateAuthToken();
return await request(server)
.post("/api/geners")
.set("x-auth-token", token)
.send(genre);
}
});
});
当我添加另一个文件进行集成测试,如下面的一个,我开始得到这个文件代码后提到的错误。
const {User} = require("../../models/user");
const {Genere} = require("../../models/genere");
const request = require("supertest");
let token;
describe("middleware", () => {
beforeEach(() => {
console.log("Before each Middleware");
token = new User().generateAuthToken();
server = require("../../index");
});
afterEach(async () => {
console.log("After each Middleware");
await Genere.deleteMany({});
await server.close();
});
const exec = async() => {
return await request(server)
.post("/api/geners")
.set("x-auth-token", token)
.send({name: "gener1"});
}
it("should return 400 if invalid JWT token is sent", async() => {
token = "invalid_token";
const res = await exec();
expect(res.status).toBe(400);
expect(res.text).toBe("Invalid auth token");
});
});
控制台错误
middleware
✕ should return 400 if invalid JWT token is sent (510ms)
● middleware › should return 400 if invalid JWT token is sent
listen EADDRINUSE: address already in use :::4000
10 | require("./startup/routes")(app);
11 | const port = process.env.port || 4000;
> 12 | const server = app.listen(port, () => {winston.info(`Listening on port ${port}`)});
| ^
13 | // exporting server object to be used in integration tests.
14 | module.exports = server;
at Function.listen (node_modules/express/lib/application.js:618:24)
at Object.<anonymous> (index.js:12:20)
at Object.beforeEach (tests/integration/middleware.test.js:11:22)
如果有人能帮助我为什么它在多次运行时失败,那么它将真正有助于我理解为什么我们需要每次打开和关闭服务器对象。
4条答案
按热度按时间2ic8powd1#
Supertest能够管理express/koa
app
本身的安装/拆卸,如果您可以导入app
的示例而无需在其上调用.listen()
。这涉及到代码的结构略有不同,因此
app
成为一个模块,与服务器.listen()
分开然后,运行服务器的入口点导入
app
,然后使用.listen()
设置服务器当supertest使用导入的
app
时,它将启动自己的服务器并侦听随机未使用的端口,而不会发生冲突。超级测试“服务器”示例也可以被多个测试重用
7xllpg7q2#
一种解决方案是运行jest,将max worker指定为1,可以在package.json中按以下方式配置:
tcomlyy63#
如果我对您的设置理解正确的话,您有多个集成测试文件,Jest将尝试并行运行这些文件(这是默认模式)。您得到的错误是有意义的,因为对于每个套件,在每个测试之前都创建了一个新的服务器示例,但是在执行不同的套件时,服务器可能已经启动。
正如官方文档中所描述的,使用
globalSetup
而不是beforeEach
是有意义的,在运行所有测试套件之前,你会初始化你的服务器一次,然后停止服务器:或者,您可以使用
--runInBand
选项和beforeAll
而不是beforeEach
来运行测试,以确保在每次测试之前只创建一个服务器,但我建议使用第一个选项。r7xajy2e4#
另一种方法可能是在测试期间侦听随机未使用的端口(端口0),如果您需要在测试期间运行服务,例如: