Javascript 如何对快速路由器路由进行单元测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35234718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:26:55  来源:igfitidea点击:

How to unit test express Router routes

javascriptnode.jsunit-testingexpresschai

提问by cusejuice

I'm new to Node and Express and I'm trying to unit test my routes/controllers. I've separated my routes from my controllers. How do I go about testing my routes?

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

config/express.js

配置/express.js

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

app/router/index.js

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

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

app/router/routes/books.js

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

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

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

  module.exports = router;

app/api/controllers/books.js

应用程序/api/控制器/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

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

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

  describe('BookRoute', function() {

  });

回答by ironchefpython

Code:

代码:

config/express.js

配置/express.js

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

module.exports = app;

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

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

Considerations:

注意事项:

If your server requires an initial state at the beginning of a set of tests (because you're executing calls which mutate server state), you'll need to write a function that will return a freshly configured app and the beginning of each group of tests. There is an NPM library: https://github.com/bahmutov/really-needthat will allow you to require a freshly instantiated version of your server.

如果您的服务器在一组测试开始时需要一个初始状态(因为您正在执行改变服务器状态的调用),您将需要编写一个函数来返回一个新配置的应用程序和每组测试的开始测试。有一个 NPM 库:https: //github.com/bahmutov/really-need,它将允许您需要一个新实例化的服务器版本。

回答by Peter Haight

This is interesting because you've separated out your controllers from your routers. The other StackOverflow article mentioned in the comments is a good way to test your controllers, I think. The thing to keep in mind with unit tests is what are you testing exactly. You shouldn't need to write tests to test the express library because presumably it has its own unit tests. So you just need to test your calls to the library. So for the books route, you just need to test this one line of code:

这很有趣,因为您已经将控制器与路由器分开了。我认为,评论中提到的另一篇 StackOverflow 文章是测试控制器的好方法。使用单元测试要记住的是你到底在测试什么。您不需要编写测试来测试 express 库,因为大概它有自己的单元测试。所以你只需要测试你对库的调用。所以对于书籍路线,你只需要测试这一行代码:

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

I looked around to see if there was an obvious way to get a list of routes from the express library, but I didn't see one. You can probably just look at the library itself and check its internals to see if you set a route correctly. Another option though is to mock it up and just check that you are calling it correctly.

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

This is going to get pretty complicated because you need to mock up a some fundamental parts of Javascript in order to test this one line of code. Here's how I did it:

这将变得非常复杂,因为您需要模拟 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);
  });
});

What's going on here is I used Jasmine's spyOn function to spyOn the _load function in module.js which is what handles all of the require calls. This is so that when we require the books router and it calls require('express') we can return our express SpyObj that we created with jasmine.createSpyObj. Once we have replaced express with our spy object, then we can have it return our Router SpyObj which will let us spy on router.get. Then we can check to make sure it is called with '/' and controller.index.

这里发生的事情是我使用 Jasmine 的 spyOn 函数来监视 module.js 中的 _load 函数,该函数处理所有的 require 调用。这样当我们需要书籍路由器并调用 require('express') 时,我们可以返回我们使用 jasmine.createSpyObj 创建的 express SpyObj。一旦我们用我们的 spy 对象替换了 express,那么我们就可以让它返回我们的 Router SpyObj,这将让我们监视 router.get。然后我们可以检查以确保它是用'/'和controller.index调用的。

This could probably be made into some sort of utility if you wanted to use this a lot.

如果您想经常使用它,这可能会被制成某种实用程序。

I usually avoid a lot of this thing by using a more object oriented approach and either I'm passing around some object everywhere that I can mock for tests or you could use some kind of dependency injection like Angular uses.

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

回答by Patrick Motard

I found this blogincredibly insightful when testing my own servers endpoints.

在测试我自己的服务器端点时,我发现这个博客非常有见地。

In the blog he addresses:

他在博客中提到:

  • How to use the endpoint testing library supertest.

  • How to programmatically spin up and tear down an express server with your needed routes before and after each endpoint test. (he also explains why you would want to do this).

  • How to avoid a common gotcha, require caching your modules required in your unit tests, leading to unintended consequences.

  • 如何使用端点测试库supertest

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

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

Hope this helps. Good luck and if you have any further questions let me know.

希望这可以帮助。祝你好运,如果您有任何其他问题,请告诉我。