如何在testingNodeJS API时模拟外部服务

我有用koa构build的JSON API,我试图用集成testing来覆盖。

一个简单的testing看起来像这样:

describe("GET: /users", function() { it ("should respond", function (done) { request(server) .get('/api/users') .expect(200, done); }); }); 

现在问题来了,当一个控制器后面的动作 – 让说在POST /用户saveUser – 使用外部资源。 例如,我需要validation用户的电话号码。

我的控制器看起来像这样:

  save: async function(ctx, next) { const userFromRequest = await parse(ctx); try { // validate data await ctx.repo.validate(userFromRequest); // validate mobile code await ctx.repo.validateSMSCode( userFromRequest.mobile_number_verification_token, userFromRequest.mobile_number.prefix + userFromRequest.mobile_number.number ); const user = await ctx.repo.create(userFromRequest); return ctx.data(201, { user }); } catch (e) { return ctx.error(422, e.message, e.meta); } } 

我希望能够嘲笑请求对象上的ctx.repo ,但我似乎无法从testing中得到它的保留,这意味着我的testing实际上正在打电话号码validation服务。

有什么方法可以去打击validation服务?

app.context是从中创buildctx的原型。 您可以通过编辑app.contextctx添加其他属性。 这对于在整个app添加ctx属性或方法非常有用,这可能是更高性能(无中间件)和/或更容易(更lessrequire() ),而牺牲更多的ctx ,这可能是被认为是反模式。

 app.context.someProp = "Some Value"; app.use(async (ctx) => { console.log(ctx.someProp); }); 

对于你的示例,你可以像这样重新定义app.context.repo.validateSMSCode ,假设你在你的testing中有以下设置行:

 import app from '../app' import supertest from 'supertest' app.context.repo.validateSMSCode = async function(ctx, next) { // Your logic here. }; const request = supertest.agent(app.listen()) 

重新定义你将在你的testing中定义的app.context.repo.validateSMSCode方法后,将工作,而不是原来的方法。

你有没有考虑使用像https://github.com/mfncooper/mockery模型库?

通常,在编写需要外部服务的testing时,我嘲笑服务客户端库模块。 例如,使用摩卡:

 mockery = require('mockery'); repo = require('your-repo-module'); before(function() { mockery.enable(); repo.validateSMSCode = function() {...}; mockery.registerMock('your-repo-module', repo); } 

这样,每次你需要你的回购模块,模拟模块将被加载,而不是原来的模块。 直到你禁用模拟,显然…