Как реализовать базовый модульный тест в javascript для оркестровки лазурной долговременной функции - PullRequest
0 голосов
/ 25 февраля 2019

Какой будет модульный тест, который будет имитировать вызовы callActivity в оркестраторе ниже, чтобы вернуть известное значение и ожидать, что оркестратор вернет это значение.

Примеры документации по долговременным функциям Azure длямодульное тестирование [1] написано на C #, и я не смог воспроизвести их в javascript, несмотря на несколько попыток.Это потому, что я не знаю, как создать оркестратор с поддельным контекстом.

  const df = require('durable-functions');

  module.exports = df.orchestrator(function* orchestratorFunctionGenerator(context) {
    const input = context.df.getInput();
    const apimApiName = input.apimApiName;
    const indexNames = yield context.df.callActivity('GetIndexNames', apimApiName);
    const indexerName = indexNames.idle;
    const indexerStatus = yield context.df.callActivity('GetIndexerStatus', indexerName);
    return indexerStatus;
  });

[1] https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-unit-testing

1 Ответ

0 голосов
/ 25 февраля 2019

Подход, который мы использовали, заключался в том, чтобы извлечь метод генератора в его собственный модуль.

module.exports = function* orchestratorFunctionGenerator(context) {
  const input = context.df.getInput();
  const apimApiName = input.apimApiName;
  const indexNames = yield context.df.callActivity('GetIndexNames', apimApiName);
  const indexerName = indexNames.idle;
  const indexerStatus = yield context.df.callActivity('GetIndexerStatus', indexerName);
  return indexerStatus;
};

, затем потребовать его

const df = require('durable-functions');
const generatorFunction = require('./generator-function');

module.exports = df.orchestrator(generatorFunction);

, а затем протестировать функцию в отдельности

const chai = require('chai');
const sinon = require('sinon');
const getIndexerStatusOrchestratorGenerator = require('../../GetIndexerStatusOrchestrator/generator-function');

const expect = chai.expect;

function iterateGenerator(generator) {
  let result = generator.next();
  while (!result.done) {
    result = generator.next(result.value);
  }
  return result;
}

describe('getIndexerStatusOrchestrator', () => {
  it('happy path should return \'inProgress\'', () => {
    const indexNames = { active: 'index-1', idle: 'index-2' };
    const apimApiName = 'api';
    const input = { apimApiName };
    const stubCallActivity = sinon.stub();
    stubCallActivity.withArgs('GetIndexNames', apimApiName).returns(indexNames);
    stubCallActivity.withArgs('GetIndexerStatus', indexNames.idle).returns('inProgress');

    const context = {
      df: {
        callActivity: stubCallActivity,
        getInput: sinon.fake.returns(input),
      },
    };

    const generator = getIndexerStatusOrchestratorGenerator(context);

    const result = iterateGenerator(generator);
    expect(result.value).to.equal('inProgress');
  });
  it('indexer status should be for the idle index', () => {
    const indexNames = { active: 'index-1', idle: 'index-2' };
    const apimIndexName = 'api';
    const input = { apimApiName: apimIndexName };
    const stubCallActivity = sinon.stub();
    stubCallActivity.withArgs('GetIndexNames', apimIndexName).returns(indexNames);
    stubCallActivity.withArgs('GetIndexerStatus', indexNames.idle);
    // use stub as a mock since we need both stub and mock behaviour
    // for 'callActivity' and this was the easier option
    stubCallActivity.withArgs('GetIndexerStatus').callsFake((method, indexerName) => {
      expect.fail(`Unexpected indexer name ${indexerName}`);
    });

    const context = {
      df: {
        callActivity: stubCallActivity,
        getInput: sinon.fake.returns(input),
      },
    };

    const generator = getIndexerStatusOrchestratorGenerator(context);

    iterateGenerator(generator);

    // expectations set above
  });
});

Как и следовало ожидать, это тривиальный пример оркестровщика.У нас есть оркестраторы, в которых гораздо больше логики, и где тесты будут иметь большее значение.

Кроме того, я лично не буду использовать метод насмешки во втором тесте и просто буду полагаться на тестирование выходов с использованием заглушек.подделать взаимодействия зависимостей.

...