什么是单元测试,它将伪造下面的编排器中对callActivity的调用以返回已知值并期望编排器返回该值。
天蓝色的持久功能文档中用于单元测试的示例[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
答案 0 :(得分:0)
我们采用的方法是将generator方法提取到其自己的模块中。
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
});
});
可以预料,这是编排器的一个简单例子。我们的编排器中包含更多逻辑,并且测试将具有更大价值。
此外,我个人不会在第二次测试中使用模拟方法,而只是依靠使用存根测试输出来伪造依赖项交互。