一个单元如何testingExpress的路线?

我正在学习Node.js,并且一直在玩Express 。 真的很喜欢这个框架,但是我很难弄清楚如何编写一个path的单元/集成testing。

能够unit testing简单的模块很容易,并已与摩卡做; 然而,我的unit testingExpress表示失败,因为我传入的响应对象不保留这些值。

testing路由function(routes / index.js):

exports.index = function(req, res){ res.render('index', { title: 'Express' }) }; 

unit testing模块:

 var should = require("should") , routes = require("../routes"); var request = {}; var response = { viewName: "" , data : {} , render: function(view, viewData) { viewName = view; data = viewData; } }; describe("Routing", function(){ describe("Default Route", function(){ it("should provide the a title and the index view name", function(){ routes.index(request, response); response.viewName.should.equal("index"); }); }); }); 

当我运行这个,“错误:检测到全局泄漏:viewName,数据”失败。

  1. 我在哪里错了,以便我能得到这个工作?

  2. 有没有更好的方法来在这个级别unit testing我的代码?

更新 1.更正后的代码片段,因为我最初忘了“it()”。

改变你的响应对象:

 var response = { viewName: "" , data : {} , render: function(view, viewData) { this.viewName = view; this.data = viewData; } }; 

它会工作。

正如其他人在评论中所build议的那样,它看起来像testingExpress控制器的标准方法是通过超级特性 。

一个示例testing可能如下所示:

 describe('GET /users', function(){ it('respond with json', function(done){ request(app) .get('/users') .set('Accept', 'application/json') .expect(200) .end(function(err, res){ if (err) return done(err); done() }); }) }); 

上行:你可以一口气testing你的整个堆栈。

下行:感觉和行为有点像集成testing。

用express来testingHTTP最简单的方法是窃取TJ的http helper

我亲自使用他的帮手

 it("should do something", function (done) { request(app()) .get('/session/new') .expect('GET', done) }) 

如果你想专门testing你的路线对象,然后通过正确的模拟

 describe("Default Route", function(){ it("should provide the a title and the index view name", function(done){ routes.index({}, { render: function (viewName) { viewName.should.equal("index") done() } }) }) }) 

我得出的结论是,真正unit testing快速应用程序的唯一方法是在请求处理程序和核心逻辑之间保持大量的分离。

因此,您的应用程序逻辑应该放在单独的模块中,这些模块可能requireunit testing,并且对Express请求和响应类的依赖性最小。

然后在请求处理程序中,您需要调用核心逻辑类的相应方法。

一旦我完成重组我的当前应用程序,我会举一个例子!

我猜这样的事情? (随意发表要点或评论,我还在探索)。

编辑

这是一个很小的例子,内联。 请参阅要点以获取更详细的示例。

 /// usercontroller.js var UserController = { _database: null, setDatabase: function(db) { this._database = db; }, findUserByEmail: function(email, callback) { this._database.collection('usercollection').findOne({ email: email }, callback); } }; module.exports = UserController; /// routes.js /* GET user by email */ router.get('/:email', function(req, res) { var UserController = require('./usercontroller'); UserController.setDB(databaseHandleFromSomewhere); UserController.findUserByEmail(req.params.email, function(err, result) { if (err) throw err; res.json(result); }); }); 

如果unit testing与快递4注意这个例子来自gjohnson :

 var express = require('express'); var request = require('supertest'); var app = express(); var router = express.Router(); router.get('/user', function(req, res){ res.send(200, { name: 'tobi' }); }); app.use(router); request(app) .get('/user') .expect('Content-Type', /json/) .expect('Content-Length', '15') .expect(200) .end(function(err, res){ if (err) throw err; }); 

我也想知道这一点,但专门为unit testing,而不是集成testing。 这就是我现在正在做的,

 test('/api base path', function onTest(t) { t.plan(1); var path = routerObj.path; t.equals(path, '/api'); }); test('Subrouters loaded', function onTest(t) { t.plan(1); var router = routerObj.router; t.equals(router.stack.length, 5); }); 

routerObj只是{router: expressRouter, path: '/api'} 。 然后,我使用var loginRouterInfo = require('./login')(express.Router({mergeParams: true})); 然后快速的应用程序调用以快速路由器为参数的初始化函数。 然后initRouter调用router.use(loginRouterInfo.path, loginRouterInfo.router); 安装子路由器。

该子路由器可以通过以下方式进行testing:

 var test = require('tape'); var routerInit = require('../login'); var express = require('express'); var routerObj = routerInit(express.Router()); test('/login base path', function onTest(t) { t.plan(1); var path = routerObj.path; t.equals(path, '/login'); }); test('GET /', function onTest(t) { t.plan(2); var route = routerObj.router.stack[0].route; var routeGetMethod = route.methods.get; t.equals(routeGetMethod, true); var routePath = route.path; t.equals(routePath, '/'); }); 

为了实现unit testing而不是集成testing,我嘲笑了请求处理程序的响应对象。

 /* app.js */ import endpointHandler from './endpointHandler'; // ... app.post('/endpoint', endpointHandler); // ... /* endpointHandler.js */ const endpointHandler = (req, res) => { try { const { username, location } = req.body; if (!(username && location)) { throw ({ status: 400, message: 'Missing parameters' }); } res.status(200).json({ location, user, message: 'Thanks for sharing your location with me.', }); } catch (error) { console.error(error); res.status(error.status).send(error.message); } }; export default endpointHandler; /* response.mock.js */ import { EventEmitter } from 'events'; class Response extends EventEmitter { private resStatus; json(response, status) { this.send(response, status); } send(response, status) { this.emit('response', { response, status: this.resStatus || status, }); } status(status) { this.resStatus = status; return this; } } export default Response; /* endpointHandler.test.js */ import Response from './response.mock'; import endpointHandler from './endpointHander'; describe('endpoint handler test suite', () => { it('should fail on empty body', (done) => { const res = new Response(); res.on('response', (response) => { expect(response.status).toBe(400); done(); }); endpointHandler({ body: {} }, res); }); }); 

然后,为了实现集成testing,您可以模拟您的endpointHandler并使用超级terminal调用terminal。