如何在这种情况下使用Jest测试Express路由器catch分支



我有一个包含两个路由的文件。

routes/index.js

const express = require('express')
const router = express.Router()
router.get('', (req, res, next) => {
try {
res.status(200).render('../views/')
} catch (error) {
next(error)
}
})
router.get('*', (req, res, next) => {
try {
res.status(404).render('../views/not-found')
} catch (error) {
next(error)
}  
})
module.exports = router

我想测试一下树枝。其中一个明显的问题是,我不能伪造router.get的回调所做的事情,因为那样我的测试将毫无意义,我会修改我想要测试的东西。

我可以向这些特定的路由发送Supertest请求,但我无法控制会发生什么。我想避免创建硬编码路由,这样我就可以检查下一个函数是否调用了中间件。如果我理解正确,如果我在try块中发生了其他事情(比如数据库查询(,那么我可以模拟来抛出错误。

但我没有任何其他事情发生在那里。以下是我无法理解的:如果我嘲笑服务器的功能,那么我不会测试我已经拥有的功能,而是测试其他功能,所以这样做没有意义。也许我误解了事情是如何运作的,但据我所知,唯一的选择是以某种方式嘲笑res.status或res.render所做的事情(截去它们,让它们抛出错误(,以某种方式模仿Supertest所做的事,但我不知道该怎么做。

如有任何帮助,我们将不胜感激!

单元测试解决方案:

route.js:

const express = require('express');
const router = express.Router();
router.get('', (req, res, next) => {
try {
res.status(200).render('../views/');
} catch (error) {
next(error);
}
});
router.get('*', (req, res, next) => {
try {
res.status(404).render('../views/not-found');
} catch (error) {
next(error);
}
});
module.exports = router;

route.test.js:

describe('64051580', () => {
afterEach(() => {
jest.resetModules();
jest.restoreAllMocks();
});
it('should render views', () => {
const express = require('express');
const mRouter = { get: jest.fn() };
jest.spyOn(express, 'Router').mockImplementationOnce(() => mRouter);
const mReq = {};
const mRes = { status: jest.fn().mockReturnThis(), render: jest.fn() };
const mNext = jest.fn();
mRouter.get.mockImplementation((path, callback) => {
if (path === '') {
callback(mReq, mRes, mNext);
}
});
require('./route');
expect(mRes.status).toBeCalledWith(200);
expect(mRes.render).toBeCalledWith('../views/');
});
it('should handle error', () => {
const express = require('express');
const mRouter = { get: jest.fn() };
jest.spyOn(express, 'Router').mockImplementationOnce(() => mRouter);
const mReq = {};
const mErr = new Error('parse');
const mRes = {
status: jest.fn().mockReturnThis(),
render: jest.fn().mockImplementationOnce(() => {
throw mErr;
}),
};
const mNext = jest.fn();
mRouter.get.mockImplementation((path, callback) => {
if (path === '') {
callback(mReq, mRes, mNext);
}
});
require('./route');
expect(mNext).toBeCalledWith(mErr);
});
it('should render 404 not found view', () => {
const express = require('express');
const mRouter = { get: jest.fn() };
jest.spyOn(express, 'Router').mockImplementationOnce(() => mRouter);
const mReq = {};
const mRes = { status: jest.fn().mockReturnThis(), render: jest.fn() };
const mNext = jest.fn();
mRouter.get.mockImplementation((path, callback) => {
if (path === '*') {
callback(mReq, mRes, mNext);
}
});
require('./route');
expect(mRes.status).toBeCalledWith(404);
expect(mRes.render).toBeCalledWith('../views/not-found');
});
});

带覆盖率报告的单元测试结果:

PASS  src/stackoverflow/64051580/route.test.js
64051580
✓ should render views (656ms)
✓ should handle error (17ms)
✓ should render 404 not found view (16ms)
----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |    90.91 |      100 |      100 |    90.91 |                   |
route.js |    90.91 |      100 |      100 |    90.91 |                16 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        4.28s, estimated 10s

最新更新