0

I'm trying to learn how to write unit tests for durable function. Here is my code:

    [FunctionName("OrchestratorFunction")]
    public async Task RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context)
    {
            var jobs = await context.CallActivityAsync<List<Job>>("JobsReaderFunction"), null);
            if (jobs != null && jobs .Count > 0)
            {
                var processingTasks = new List<Task>();
                foreach (var job in jobs)
                {                    
                    Task processTask = context.CallSubOrchestratorAsync("SubOrchestratorFunction"), job);
                    processingTasks.Add(processTask);
                }
                await Task.WhenAll(processingTasks);               
            }
    }

    [FunctionName("SubOrchestratorFunction")]
    public async Task RunSubOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context)        
    {
            var job = context.GetInput<Job>();
            var group = await context.CallActivityAsync<Group>("GroupReaderFunction"), job);
            await context.CallActivityAsync("EmailSenderFunction", group);
            var canWriteToGroup = await context.CallActivityAsync<bool>("GroupVerifierFunction", job);            
            await context.CallActivityAsync("JobStatusUpdaterFunction", new JopStatusUpdaterRequest { CanWriteToGroup = canWriteToGroup, Job = job });
            await context.CallActivityAsync("TopicMessageSenderFunction", job);
    }    

How do I write a test that covers Orchestrator, SubOrchestrator and Activity functions? Please let me know.

Here is my test so far:

        [TestMethod]
        public async Task VerifyOrchestrator()
        {            
            var jobs = <code to get jobs>
            var context = new Mock<IDurableOrchestrationContext>();           
            context.Setup(m => m.CallActivityAsync<List<Job>>("JobsReaderFunction", It.IsAny<object>())).ReturnsAsync(jobs);
            await _orchestratorFunction.RunOrchestrator(context.Object);
        }

UPDATE:

I updated the test method to:

        [TestMethod]
        public async Task VerifyJobs()
        {            
            var jobs = <code to get jobs>
            var context = new Mock<IDurableOrchestrationContext>();           
            context.Setup(x => x.CallSubOrchestratorAsync("SubOrchestratorFunction"), It.IsAny<object>())).Returns(() => _orchestratorFunction.RunSubOrchestrator(context.Object));            
            await _orchestratorFunction.RunOrchestrator(context.Object);
        }

which gives me an error:

enter image description here

context.Setup(x => x.CallSubOrchestratorAsync("SubOrchestratorFunction", It.IsAny<object>())).Returns(async () => await It.IsAny<Task>());
await _orchestratorFunction.RunOrchestrator(context.Object);
context.Verify(m => m.CallSubOrchestratorAsync("SubOrchestratorFunction", It.IsAny<string>(), It.IsAny<object>()),Times.Once);

The above gives a null exception.

user989988
  • 3,006
  • 7
  • 44
  • 91

1 Answers1

1

The context is mocked acording to the line:

var context = new Mock<IDurableOrchestrationContext>();           

This means that when you execute Context.CallSubOrchestratorAsync("SubOrchestratorFunction") moq search for setup for the method. Because the method doesn't have any setup, it runs nothing and returns the default return value.

If you want to execute RunSubOrchestrator, you should setup it:

context.Setup(x => x.CallSubOrchestratorAsync("SubOrchestratorFunction", It.IsAny<object>())).Returns(() => _orchestratorFunction.RunSubOrchestrator(context.Object))
itaiy
  • 1,152
  • 1
  • 13
  • 22
  • Thanks! When I add that line, it gives me error: no overload for method 'CallSubOrchestratorAsync' takes 1 argument. Could you please let me know why is that? – user989988 Jun 11 '21 at 06:16
  • Fixed, the method signature wasn't clear from the question. – itaiy Jun 11 '21 at 06:26
  • I get the above error after adding that line – user989988 Jun 11 '21 at 15:22
  • I don't know your full implementation. But from your implementation, I understand that you want to run `RunSubOrchestrator`. So you need to run it as part of the setup. – itaiy Jun 13 '21 at 06:11
  • Could you please let me know what code I should provide? – user989988 Jun 14 '21 at 07:08
  • `context.Setup(x => x.CallSubOrchestratorAsync("SubOrchestratorFunction", It.IsAny())).Returns(() => \* Execute RunSubOrchestrator *\)` – itaiy Jun 14 '21 at 07:17