作为将旧应用程序从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();
这一切都很好,但我想用我的单元测试来测试中间件,也许是因为我对Koa和Generator函数都还不太新,我很难弄清楚如何做到这一点。
我知道如果我导入错误处理中间件,我需要传递一个会抛出错误的函数,但是如何执行传递的函数?是否需要关闭一些描述?如何断言/期望为状态代码等设置的值?
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);
});
});
答案 0 :(得分:0)
Koa中间件是生成器(多次返回/生成)并且不像函数那样运行,因此为它们编写单元测试感觉很奇怪。就个人而言,我只需要端到端的测试用例。
但是,以下情况可能适用于您的情况。
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包装了生成器函数,这改变了语义,所以单元测试不是那么有用(主观)
答案 1 :(得分:0)
您可以使用koa.js 1.x使用的库https://www.npmjs.com/package/co来包装您的生成器函数并模拟上下文对象。
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))
});
});
答案 2 :(得分:0)
这就是我用Jest解决此问题的方法,我只是创建了一个自定义res对象并将其传递给错误处理程序:
const error = require('../../../middleware/error');
describe('error middleware', () => {
it(' return 500 if there is unhandled error', async () => {
const res = {
status: (c) => {this.c = c; return {send: (s) => {this.s = s; return this}}} ,
c: 200,
s: 'OK',
};
const req = {};
const next = jest.fn();
const err = () => {
throw new Error()
};
const errorHandler = error(err, req, res, next);
expect(errorHandler).toMatchObject({c: 500, s: 'Something failed'});
});
});