如何单元测试表达路由器的路由

时间:2016-02-05 22:34:25

标签: javascript node.js unit-testing express chai

我是Node和Express的新手,我正在尝试对我的路由/控制器进行单元测试。我把我的路线与我的控制器分开了。我该如何测试我的路线?

配置/ express.js

UIWebView

应用/路由器/ index.js

false

应用/路由器/路由/ books.js

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

应用/ API /控制器/ books.js

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

应用/测试/ API /路由/ books.test.js

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

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

  module.exports = router;

4 个答案:

答案 0 :(得分:9)

代码:

<强>配置/ express.js

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

module.exports = app;

应用/测试/ API /路由/ 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,允许您需要一个新实例化的服务器版本。

答案 1 :(得分:4)

这很有趣,因为您已将控制器与路由器分离。我认为评论中提到的另一篇StackOverflow文章是测试控制器的好方法。单元测试需要牢记的是你正在测试什么。您不应该编写测试来测试快速库,因为它可能有自己的单元测试。所以你只需要测试你对库的调用。因此,对于书籍路线,您只需要测试这一行代码:

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

我环顾四周,看看是否有明显的方法从快递库中获取路线列表,但我没有看到。您可以只查看库本身并检查其内部以查看是否正确设置了路径。另一个选择是模拟它,只是检查你是否正确调用它。

这将变得相当复杂,因为你需要模拟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函数来调试module.js中的_load函数,它处理所有需要的调用。这样,当我们需要books路由器并调用require('express')时,我们可以返回我们用jasmine.createSpyObj创建的快速SpyObj。一旦我们用我们的间谍对象替换了express,那么我们可以让它返回我们的路由器SpyObj,这将让我们窥探router.get。然后我们可以检查以确保使用'/'和controller.index调用它。

如果你想大量使用它,这可能会成为某种实用程序。

我通常通过使用更面向对象的方法来避免很多这样的事情,要么我在任何地方传递一些我可以模拟测试的对象,或者你可以使用像Angular一样的依赖注入。

答案 2 :(得分:2)

我在测试自己的服务器端点时发现this blog非常有洞察力。

在博客中他说:

  • 如何使用端点测试库supertest

  • 如何在每次端点测试之前和之后以编程方式使用所需路由启动和拆除快速服务器。 (他还解释了你为什么要这样做)。

  • 如何避免常见问题,需要缓存单元测试中所需的模块,从而导致意外后果。

希望这会有所帮助。祝你好运,如果你有任何进一步的问题,请告诉我。

答案 3 :(得分:1)

如果您只想对路由的存在及其方法进行单元测试,您可以执行以下操作:

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

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();
  });
});