使用Jest编写消息保存POST接口测试用例时遇TypeError错误求助
解决Express+MongoDB接口Jest测试报错"TypeError: app.address is not a function"
问题概述
为基于Express+MongoDB的消息保存POST接口编写Jest测试用例时,运行测试触发以下错误:
TypeError: app.address is not a function
报错原因
你的server.js文件未导出Express的app实例,而是直接调用app.listen()启动服务器。当测试用例中require("../server")时,返回值为undefined,而supertest需要传入有效的Express app实例才能创建请求,因此触发该错误。
核心修复步骤
修改server.js导出app实例
调整server.js代码,将Express app实例导出,并仅在直接运行该文件时启动服务器:
const express = require("express"); const dotenv = require("dotenv"); const connectDB = require("./config/db"); const messageRouter = require("./routes/message.routes"); const { notFound , errorHandler} = require("./middleware/errorMiddleware"); dotenv.config(); connectDB(); const app = express(); app.use(express.json()); app.get("/", (req, res) => { res.send("API is Running"); }); app.use("/api/message", messageRouter); app.use(notFound); app.use(errorHandler); // 导出app实例供测试使用 module.exports = app; // 仅当直接运行server.js时启动服务器 if (require.main === module) { const PORT = process.env.PORT || 5000; app.listen(PORT, console.log(`server is running on PORT ${PORT}`)); }
测试用例的额外修正
除核心修复外,测试用例还有几个问题需要调整才能正常运行:
1. 处理认证中间件
/api/message/save接口使用了protect中间件,测试时需模拟已认证用户,可通过mock中间件实现:
// 在测试文件顶部添加 jest.mock("../middleware/authenticationMiddleware", () => ({ protect: (req, res, next) => { req.user = { _id: new mongoose.Types.ObjectId() }; // 模拟用户ID next(); }, }));
2. 修正数据库操作
- 使用测试专用数据库:在
.env.test中配置独立的测试MongoDB URI,避免污染生产数据 - 清理测试数据:在
afterEach中删除测试生成的消息,而非关闭数据库连接afterEach(async () => { await Message.deleteMany({}); // 清理Message集合 });
3. 修正断言逻辑
测试中的expect(res.body.name).toBe("Message 1")无效,因为Message模型没有name字段,需断言存在的字段:
expect(res.statusCode).toBe(201); expect(res.body.writerName).toBe("wN"); expect(res.body.description).toBe("Description");
4. 生成有效的ObjectId
user字段为ObjectId类型,需确保传入有效值(通过mock中间件已自动处理)。
最终修正后的测试用例示例
const mongoose = require("mongoose"); const request = require("supertest"); const app = require("../server"); // 现在能正确获取app实例 const Message = require("../models/Message.Model"); require("dotenv").config(); beforeEach(async () => { await mongoose.connect(process.env.MONGO_URI); }); afterEach(async () => { await Message.deleteMany({}); await mongoose.connection.close(); }); // Mock认证中间件 jest.mock("../middleware/authenticationMiddleware", () => ({ protect: (req, res, next) => { req.user = { _id: new mongoose.Types.ObjectId() }; next(); }, })); describe("POST /api/message/save", () => { it("should create a message", async () => { const res = await request(app).post("/api/message/save").send({ writerName: "wN", date: "12", description: "Description", }); expect(res.statusCode).toBe(201); expect(res.body.writerName).toBe("wN"); expect(res.body.description).toBe("Description"); expect(mongoose.Types.ObjectId.isValid(res.body.user)).toBe(true); }); });
内容的提问来源于stack exchange,提问作者user19673961
相关产品推荐
相关产品推荐

