簡體   English   中英

如何對快速路由器路由進行單元測試

[英]How to unit test express Router routes

我是 Node 和 Express 的新手,我正在嘗試對我的路由/控制器進行單元測試。 我已經將我的路線與我的控制器分開了。 如何測試我的路線?

配置/express.js

  var app = express();
  // middleware, etc
  var router = require('../app/router')(app);

應用程序/路由器/index.js

  module.exports = function(app) {
    app.use('/api/books', require('./routes/books'));
  };

應用程序/路由器/路由/books.js

  var controller = require('../../api/controllers/books');
  var express = require('express');
  var router = express.Router();

  router.get('/', controller.index);

  module.exports = router;

應用程序/api/controllers/books.js

// this is just an example controller
exports.index = function(req, res) {
    return res.status(200).json('ok');
};

app/tests/api/routes/books.test.js

  var chai = require('chai');
  var should = chai.should();
  var sinon = require('sinon');

  describe('BookRoute', function() {

  });

代碼:

配置/express.js

var app = express();
// middleware, etc
var router = require('../app/router')(app);

module.exports = app;

app/tests/api/routes/books.test.js

var chai = require('chai');
var should = chai.should();
var sinon = require('sinon');
var request = require('supertest');
var app = require('config/express');

describe('BookRoute', function() {
    request(app)
        .get('/api/books')
        .expect('Content-Type', /json/)
        .expect('Content-Length', '4')
        .expect(200, "ok")
        .end(function(err, res){
           if (err) throw err;
        });
});

注意事項:

如果你的服務器在一組測試開始時需要一個初始狀態(因為你正在執行改變服務器狀態的調用),你需要編寫一個函數來返回一個新配置的應用程序和每組的開始測試。 有一個 NPM 庫: https ://github.com/bahmutov/really-need,它允許您需要一個新實例化的服務器版本。

如果您只想對路由的存在及其方法進行單元測試,您可以執行以下操作:

auth.router.js

import { Router } from 'express';

const router = Router();

router.post('/signup', signupValidation, signupUser);
router.post('/login', loginValidation, loginUser);
router.post('/reset', resetValidation, setPasswordReset);

export default router;

auth.router.spec.js

test('has routes', () => {
  const routes = [
    { path: '/signup', method: 'post' },
    { path: '/login', method: 'post' },
    { path: '/reset', method: 'post' },
  ]

it.each(routes)('`$method` exists on $path', (route) => {
  expect(router.stack.some((s) => Object.keys(s.route.methods).includes(route.method))).toBe(true)
  expect(router.stack.some((s) => s.route.path === route.path)).toBe(true)
})

注意:在示例測試名稱中使用$variables僅適用於 Jest ^27.0.0

編輯:感謝 Keith Yeh 建議將其放入each()語句中。 我已經相應地更新了代碼,舊代碼如下:

auth.router.spec.js (OLD)

import router from '../auth.router';

test('has routes', () => {
  const routes = [
    { path: '/signup', method: 'post' },
    { path: '/login', method: 'post' },
    { path: '/reset', method: 'post' }
  ]

  routes.forEach((route) => {
    const match = router.stack.find(
      (s) => s.route.path === route.path && s.route.methods[route.method]
    );
    expect(match).toBeTruthy();
  });
});

這很有趣,因為您已將控制器與路由器分開。 我認為評論中提到的另一篇 StackOverflow 文章是測試控制器的好方法。 單元測試要記住的是你到底在測試什么。 您不需要編寫測試來測試 express 庫,因為它可能有自己的單元測試。 所以你只需要測試你對圖書館的調用。 所以對於書籍路線,你只需要測試這一行代碼:

router.get('/', controller.index);

我環顧四周,看看是否有一種明顯的方法可以從 express 庫中獲取路線列表,但我沒有看到。 您可能只需查看庫本身並檢查其內部結構,看看您是否正確設置了路由。 另一個選擇是模擬它並檢查您是否正確調用它。

這將變得非常復雜,因為您需要模擬 Javascript 的一些基本部分才能測試這一行代碼。 我是這樣做的:

describe('BookRoute', function() {
  it("should route / to books controller index", function() {
    var controller = require('../../../api/controllers/books');
    var orig_this = this;
    var orig_load = require('module')._load;
    var router = jasmine.createSpyObj('Router', ['get']);
    var express = jasmine.createSpyObj('express', ['Router']);
    express.Router.and.returnValues(router);
    spyOn(require('module'), '_load').and.callFake(function() {
      if (arguments[0] == 'express') {
        return express;
      } else {
        return orig_load.apply(orig_this, arguments);
      }
    });
    require("../../../router/routes/books");
    expect(router.get).toHaveBeenCalledWith('/', controller.index);
  });
});

這里發生的事情是我使用 Jasmine 的 spyOn 函數來 spyOn module.js 中的 _load 函數,它處理所有的 require 調用。 這樣當我們需要圖書路由器並且它調用 require('express') 時,我們可以返回我們使用 jasmine.createSpyObj 創建的 express SpyObj。 一旦我們將 express 替換為我們的 spy 對象,我們就可以讓它返回我們的 Router SpyObj,這將讓我們在 router.get 上進行間諜活動。 然后我們可以檢查以確保它是用'/'和controller.index調用的。

如果您想經常使用它,這可能會變成某種實用程序。

我通常通過使用更面向對象的方法來避免很多這種事情,或者我在任何地方傳遞一些我可以模擬測試的對象,或者你可以使用某種依賴注入,比如 Angular 使用。

在測試我自己的服務器端點時,我發現這個博客非常有見地。

在博客中,他提到:

  • 如何使用端點測試庫supertest

  • 如何在每個端點測試之前和之后以編程方式啟動和拆除具有所需路由的快速服務器。 (他還解釋了你為什么要這樣做)。

  • 如何避免常見的陷阱,需要緩存單元測試中所需的模塊,從而導致意想不到的后果。

希望這可以幫助。 祝你好運,如果您有任何其他問題,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM