如何在考虑测试的情况下设计微服务

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.withArgsstub.callsFake(fakeFunction) 使其更加灵活。