如何在考虑测试的情况下设计微服务
how to design microservices with testing in mind
我有一项服务使用 cote
库调用另一项服务。我想知道如何设计服务以便于测试。
'use strict';
const logger = require('../../../helper/logger');
const Player = require('../../model/player_model/player_model');
const crypto = require('./../../../helper/crypto_helper');
const cote = require('cote');
let requester = new cote.Requester({name: 'findOnePlayer requester'});
/**
* Creates new player in database
* @param username / must be unique
* @param password
* @returns {Promise<Player>}
*/
module.exports.createPlayer = async (username, password) => {
if (!(username && password && username.length && password.length)) {
throw new Error('Both username and password are required');
}
const request = {type: 'findOnePlayer', username: username};
const existingPlayer = await requester.send(request);
if (existingPlayer) {
throw new Error('Username is already taken');
}
const password_salt = crypto.genRandomString(16);
/** Gives us salt of length 16 */
const password_data = crypto.sha512(password, password_salt);
const player = new Player({username: username, password_hash: password_data.password_hash, password_salt: password_data.salt});
// save user
return await player.save();
};
我想模拟请求者对象的这个方法const existingPlayer = await requester.send(request);
。但是请求者对象被用作 cote
库的构造函数。
任何帮助,或指导我应该成为什么样的人looking/investigating?
谢谢
你可以使用Sinon.js' Stubs来stub请求者的send()函数。
我会用一个简单的例子来演示。此文件包含请求者和响应者,并且仅包含 returns "bar"。它还导出请求者,因为我们需要访问它以便存根。
const cote = require('cote');
// Responder
const timeService = new cote.Responder({ name: 'Time Service' });
timeService.on('test', async () => {
return 'bar'
});
// Requester
const requester = new cote.Requester({ name: 'Client' });
async function test() {
return requester.send({ type: 'test' })
}
module.exports = { test, requester } // Export the requester
然后实际测试可以访问请求者并可以使用 sinons stub(obj, "method")
和 stub.returns('whatever')
函数:
const test = require('ava')
const sinon = require('sinon')
const foo = require('../')
test('test function should return bar when unstubbed and foo when stubbed', async t => {
// Unstubbed call
const returnValue = await foo.test()
t.is(returnValue, 'bar')
// Stub requester objects send function
var stub = sinon.stub(foo.requester, "send");
// Make it return whatever you like
stub.returns('foo')
// Test it
const stubbedValue = await foo.test()
t.is(stubbedValue, 'foo')
// Remove the stub
stub.restore();
// Original unstubbed call
const returnValue = await foo.test()
t.is(returnValue, 'bar')
});
Check out the docs,因为您可能还想使用 stub.withArgs
或 stub.callsFake(fakeFunction)
使其更加灵活。
我有一项服务使用 cote
库调用另一项服务。我想知道如何设计服务以便于测试。
'use strict';
const logger = require('../../../helper/logger');
const Player = require('../../model/player_model/player_model');
const crypto = require('./../../../helper/crypto_helper');
const cote = require('cote');
let requester = new cote.Requester({name: 'findOnePlayer requester'});
/**
* Creates new player in database
* @param username / must be unique
* @param password
* @returns {Promise<Player>}
*/
module.exports.createPlayer = async (username, password) => {
if (!(username && password && username.length && password.length)) {
throw new Error('Both username and password are required');
}
const request = {type: 'findOnePlayer', username: username};
const existingPlayer = await requester.send(request);
if (existingPlayer) {
throw new Error('Username is already taken');
}
const password_salt = crypto.genRandomString(16);
/** Gives us salt of length 16 */
const password_data = crypto.sha512(password, password_salt);
const player = new Player({username: username, password_hash: password_data.password_hash, password_salt: password_data.salt});
// save user
return await player.save();
};
我想模拟请求者对象的这个方法const existingPlayer = await requester.send(request);
。但是请求者对象被用作 cote
库的构造函数。
任何帮助,或指导我应该成为什么样的人looking/investigating?
谢谢
你可以使用Sinon.js' Stubs来stub请求者的send()函数。
我会用一个简单的例子来演示。此文件包含请求者和响应者,并且仅包含 returns "bar"。它还导出请求者,因为我们需要访问它以便存根。
const cote = require('cote');
// Responder
const timeService = new cote.Responder({ name: 'Time Service' });
timeService.on('test', async () => {
return 'bar'
});
// Requester
const requester = new cote.Requester({ name: 'Client' });
async function test() {
return requester.send({ type: 'test' })
}
module.exports = { test, requester } // Export the requester
然后实际测试可以访问请求者并可以使用 sinons stub(obj, "method")
和 stub.returns('whatever')
函数:
const test = require('ava')
const sinon = require('sinon')
const foo = require('../')
test('test function should return bar when unstubbed and foo when stubbed', async t => {
// Unstubbed call
const returnValue = await foo.test()
t.is(returnValue, 'bar')
// Stub requester objects send function
var stub = sinon.stub(foo.requester, "send");
// Make it return whatever you like
stub.returns('foo')
// Test it
const stubbedValue = await foo.test()
t.is(stubbedValue, 'foo')
// Remove the stub
stub.restore();
// Original unstubbed call
const returnValue = await foo.test()
t.is(returnValue, 'bar')
});
Check out the docs,因为您可能还想使用 stub.withArgs
或 stub.callsFake(fakeFunction)
使其更加灵活。