Supertest测试报404错误排查(Postman请求正常)
问题:Supertest调用接口返回404,但Postman请求正常
我正在为基于Express、Sequelize的PostgreSQL数据插入接口编写单元测试,使用Supertest调用/calculation接口时,测试抛出「expected 200 OK, got 404 Not Found」错误,但Postman请求该接口可正常返回200结果。以下是相关代码,请问问题出在哪里?
测试代码
const app = require('../../index') const supertest = require('supertest') const request = supertest(app) it('Positive flow', (done) => { let reqObj = { "name": "Qwerty", "class": 2 } let resObj = { "success": "yes", "message": "done" } const response = request.post('/calculation') .send(reqObj) .expect(200) .end((err, res) => { if (err) return done(err) response.expect(200) response.expect(expect.objectContaining(resObj)) return done() }) })
index.js
const express = require('express'); const router = require('./router') const PORT = 7000 const app = express(); app.use(express.json()); app.use('/', router); module.exports = app; app.listen(PORT, () => console.log(`PORT:${PORT}`));
router.js
const express = require('express') const router = express.Router() const func = require('./calculation') router.post('/calculation', func.calc) module.exports = router
calculation业务代码
const models = require('../models') const calc = async (req, res) => { try { const calculation = await models.USER_LICENSE.create({ name: req.name, class: req.class, }); return res.status(200).json({"success": "yes", "message":"done"}) } catch (error) { return res.status(400).json({"success": "no", "message":"fail"}) } }
问题原因及解决方案
1. 路由匹配失败(404)的核心原因
- app实例导入路径错误:检查测试文件中
require('../../index')的相对路径是否正确。如果测试文件的目录层级与index.js不匹配,会导致导入的不是正确的Express app实例,自然无法匹配路由。- 解决:确认测试文件与项目根目录index.js的相对位置,调整导入路径至正确值。
- 请求路径不匹配:若你实际接口路径是
/post/calculation(如问题描述中提到的),但测试代码中请求的是/calculation,会直接导致404。- 解决:确认接口实际路径,将测试中的请求路径改为对应值,或检查router的挂载逻辑是否正确。
2. 测试代码的语法错误
- 错误的断言对象:
end回调中使用response.expect(200)是错误的,response是未完成的请求对象,应使用回调参数里的res(响应对象)进行断言。 - 断言方法使用错误:
expect.objectContaining需要通过测试框架(如Jest)的expect调用,且应断言res.body而非请求对象。
修正后的测试代码:
const app = require('../../index') const supertest = require('supertest') const request = supertest(app) it('Positive flow', (done) => { const reqObj = { "name": "Qwerty", "class": 2 } const resObj = { "success": "yes", "message": "done" } request.post('/calculation') .send(reqObj) .expect(200) .end((err, res) => { if (err) return done(err) expect(res.body).toEqual(expect.objectContaining(resObj)) done() }) })
3. 业务代码的潜在问题(虽未导致404,但会引发插入失败)
calculation.js中直接使用req.name和req.class获取参数,但通过express.json()解析的请求体数据存储在req.body中,这样写会导致Sequelize因缺少必填参数抛出错误,返回400状态码。
修正后的calculation代码:
const models = require('../models') const calc = async (req, res) => { try { const calculation = await models.USER_LICENSE.create({ name: req.body.name, class: req.body.class, }); return res.status(200).json({"success": "yes", "message":"done"}) } catch (error) { console.error(error) return res.status(400).json({"success": "no", "message":"fail"}) } } module.exports = { calc }
4. 优化建议
将index.js中的服务启动逻辑改为条件判断,避免测试时自动启动服务:
if (require.main === module) { app.listen(PORT, () => console.log(`PORT:${PORT}`)); }
内容的提问来源于stack exchange,提问作者Renee
相关产品推荐
相关产品推荐

