Moin Throw async exception in one of the tasks when calling Task.WhenAll

I have a series of tasks that I pass to the challenge of Task.WhenAll. in my tests, I set the first task to throw an exception, but my Tasks.WhenAll call is not completed for all tasks and immediately breaks when an exception occurs, I assumed that all tasks will be completed and returned when the Tasks.WhenAll call is created, therefore I think Moq cannot distinguish between an asynchronous metacharacter and non-synchronous exceptions.

I want to be able to allow all tasks to be completed, and as soon as they are all completed, I want to capture the failed tasks and extract their exceptions and act accordingly. Is my implementation correct and the MOQ is not able to handle or do I need to fix my implementation and the problem is not in the layout?

public async Task StartAsync(TextWriter log) { log = TextWriter.Synchronized(log); var processorTaks = _processors.Select(x => x.StartAsync(log)).ToList(); Task.WhenAll(processorTaks).Wait(); var innerExceptions = processorTaks.Where(x => x.Exception != null) .Select(x => x.Exception.InnerException) .ToList(); if (innerExceptions.Any()) { innerExceptions.AddRange(_processors.SelectMany(x => x.NotifierException).ToList()); var formattedExceptions = innerExceptions .Select(ex => $"{ex.Message}<\br>{ex.StackTrace}") .Distinct(); IEnumerable<Task> sendEmailTaks = _alertEmailAddresses .Split('|') .Select( x => _smtpClient.SendMailAsync($"Notifications failed with {innerExceptions.Count()} exceptions", string.Join("<\br>", formattedExceptions), x)); var retry = _createWebRetry(); await retry.RetryAsync(() => Task.WhenAll(sendEmailTaks), CancellationToken.None); } } 

my setup for processors

  FirstProcessor.Setup(x => x.StartAsync(It.IsAny<TextWriter>())).Throws(new Exception("some exception happened.")); SecondProcessor.Setup(x => x.StartAsync(It.IsAny<TextWriter>())).Returns(Task.FromResult(default(object))); 
+5
source share
2 answers

As Bruno correctly pointed out, the problem is that the mocked StartAsync synchronously throws an exception without returning a faulty task.

However, the correct code cannot use the new Task (which will cause it to freeze, since the task never starts). Use Task.FromException :

 FirstProcessor.Setup(x => x.StartAsync(It.IsAny<TextWriter>())).Returns( Task.FromException(new Exception("some exception happened.")) ); 
+9
source

Task.WhenAll will call StartAsync , which will issue. The exception applies to the calling thread. Before creating a task.

You want StartAsync to return Task :

 firstProcessor.Setup(x => x.StartAsync(It.IsAny<TextWriter>())).Returns(new Task(() => { throw new Exception("err"); })); 
+3
source

Source: https://habr.com/ru/post/1246480/


All Articles