【问题标题】:How to test Express router catch branch in this scenario using Jest?如何在这种情况下使用 Jest 测试 Express 路由器 catch 分支?
【发布时间】:2021-01-11 01:11:06
【问题描述】:

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

路由/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

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

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

但我没有任何额外的事情发生在那里。这是我无法理解的:如果我模拟服务器所做的事情,那么我不会测试我已经拥有的东西,而是测试其他东西,所以这样做没有意义。也许我误解了事情是如何工作的,但据我所知,唯一的选择是以某种方式模拟 res.status 或 res.render 所做的事情(存根它们以便他们抛出错误),所以以某种方式模拟 Supertest 所做的事情,但我不知道该怎么做。

任何帮助将不胜感激!

【问题讨论】:

  • 您真正想通过测试断言什么?是否在异常情况下调用中间件?
  • 是的。我认为每当抛出错误并且存在错误处理中间件时,错误处理中间件都会捕获它,因此这不是触发它的唯一方法。另外,也许我可以通过某种方式检查错误处理中间件是否被调用过一次,尽管手动测试测试框架是否会在 catch 中运行该行会很好。我知道它并没有真正的实际目的,但是如果出现类似的问题,无论如何都可以这样做

标签: javascript node.js express jestjs supertest


【解决方案1】:

单元测试解决方案:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 2020-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多