是否可以通过 "fake" 请求直接从代码调用 Express Router?

Is it possible to call Express Router directly from code with a "fake" request?

this question 相切,我想知道是否有一种方法可以在不实际通过 HTTP 的情况下触发 Express Router?

路由器有 "private" method named handle that accepts a request, a response, and a callback. You can take a look at the tests that Express has for its Router。一个例子是:

it('should support .use of other routers', function(done){
    var router = new Router();
    var another = new Router();

    another.get('/bar', function(req, res){
      res.end();
    });
    router.use('/foo', another);

    router.handle({ url: '/foo/bar', method: 'GET' }, { end: done });
  });

Express 团队使用 SuperTest to perform integration tests on the Router。据我了解,SuperTest 仍然使用网络,但他们会为您处理所有这些,因此它的行为就好像测试都在内存中一样。 SuperTest 似乎被广泛使用并且是一种可以接受的测试路线的方法。

顺便说一句,你没有说你试图测试什么,但如果你的目标是测试一些路由,SuperTest 的替代方法可能是将路由中的逻辑提取到一个单独的模块中,该模块可以是独立于 Express 进行测试。

变化:

routes
|
-- index.js

至:

routes
|
-- index.js
|
controllers
|
-- myCustomController.js

然后测试可以简单地以 myCustomController.js 为目标并注入任何必要的依赖项。

翻到Express的源码,才发现确实有一个API,简直如我所愿。它记录在 the tests for express.Router.

/** 
* @param {express.Router} router 
*/
function dispatchToRouter(router, url, callback) {

    var request = {
        url  : url,
        method : 'GET'
    };

    // stub a Response object with a (relevant) subset of the needed
    // methods, such as .json(), .status(), .send(), .end(), ...
    var response = {
        json : function(results) {
            callback(results);
        }
    };

    router.handle(request, response, function(err) {
        console.log('These errors happened during processing: ', err);
    });
}

但是...缺点是,正是它首先没有记录的原因:它是 Router.prototype 的私有函数:

/**
 * Dispatch a req, res into the router.
 * @private
 */

proto.handle = function handle(req, res, out) {
  var self = this;
  ...
}

所以依赖这个代码并不是世界上最安全的事情。

您完全可以使用 run-middleware 模块。您通常创建一个 Express 应用程序,然后您可以使用您的参数调用该应用程序

it('should support .use of other routers', function(done){
    var app=require('express')()      
    app.get('/bar', function(req, res){
      res.status(200).end();
    });
    app.runMiddleware('/bar',{options},function(responseCode,body,headers){
        console.log(responseCode) // Should return 200
        done()
    })
  });

更多信息:

披露:我是该模块的维护者和第一个开发者。