如何testing自定义Koa中间件的error handling?

作为从ExpressJs到Koa JS(v1)的旧应用程序迁移的一部分。 我写了一个中间件来处理发生的任何错误。 它看起来像这样:

module.errors = function * (next) { try { yield next; } catch (err) { switch(err && err.message) { case: 'Bad Request': this.status = 400; this.body = {message: 'Bad Request'}; brea; default: this.status = 500; this.body = {message: 'An error has occurred'}; } this.app.emit('error', err, this); } } 

它被包含在我的应用程序中,如下所示:

 const app = require('koa')(); const router = require('koa-router'); const { errors } = require('./middleware/errors'); app.use(errors) .use(router.routes()); app.get('/some-request', function *(next){ // request that could error }); app.listen(); 

这一切都很好,但我想用我的unit testing来testing中间件,也许因为我对Koa和Generator函数还是比较新的,我正在努力弄清楚如何做到这一点。

我知道,如果我导入error handling中间件,我需要传递一个函数,会抛出一个错误,但是如何执行传递的函数呢? 是否需要closures一些描述? 我如何声明/期望为状态码等设置的值?

 const { expect } = require('chai'); const { errors } = require('../middleware/errors'); describe('errors middleware', () => { it('returns a 500 on a generic error', () => { let thrower = function(){ throw new Error() } let errorHandler = errors(thrower()); // mass of confusion expect(errorHandler.next()).to.throw(Error); }); }); 

Koa中间件是生成器(返回/产生多次),并不像函数那样工作,所以编写unit testing感觉很奇怪。 就我个人而言,我足够的是端到端的testing用例。

但是,以下可能适用于你的情况。

 const { expect } = require('chai'); const { errors } = require('../middleware/errors'); describe('errors middleware', () => { it('returns a 500 on a generic error', () => { let ctx = { body: {}, status: 404 }; let errorMidIterator = errors().call(ctx, 'NEXT_MID'); // test that it correctly yields to next middleware expect(errorMidIterator.next().value).should.equal('NEXT_MID'); // simualte an error and test if it correctly sets the body expect(errorMidIterator.throw(new Error()).done).to.equal(true); expect(ctx.status).should.equal(500); }); }); 

作为一个方面说明,我认为最好从文件中导出中间件工厂,而不是普通的中间件生成器函数。 前者给你更多的控制(即你可以通过Factory函数参数来注入一些依赖项,在本例中是thrower()函数)。 我的中间件文件看起来像这样。

 module.exports = function MyMiddleware(options) { return function *MyMiddleware(next) { // options.config.foo // options.httpclient.get(..) }; } 

最后,koa用co来封装生成器函数,这会改变语义,所以unit testing不是那么有用(主观的)

你可以使用这个库https://www.npmjs.com/package/co koa.js 1.x来包装你的生成器函数和模拟上下文对象。

 const co = require('co'); const Emitter = require('events'); const { expect } = require('chai'); const { errors } = require('../middleware/errors'); const wrapped = co.wrap(errors); const mockApp = new Emitter(); describe('errors middleware', () => { it('returns a 500 on a generic error', (done) => { const ERROR_MSG = 'middleware error'; const ctx = {app: mockApp}; const next = function* () { throw new Error(ERROR_MSG); } wrapped.call(ctx, next) .then(() => { try { expect(ctx.status).to.equal(500); expect(ctx.body.message).to.equal(ERROR_MSG); done(); } catch (err) { done(err); } }) .catch(err => done(err)) }); });