Moq在调用Task.WhenAll的任务之一中抛出异步异常

Xer*_*xes 6 c# moq task-parallel-library

我有一些任务,我将传递给Task.WhenAll调用.在我的测试中,我正在设置抛出异常的第一个任务,但我对所有任务的Tasks.WhenAll调用没有完成,并且在抛出异常时立即中断,我的假设是所有任务都将完成并返回调用Tasks.WhenAll,所以我认为Moq无法区分抛出异步和异步异常.

我希望能够允许所有任务运行,一旦完成所有任务,我想抓住故障任务并提取其异常并采取相应措施.我的实现是否正确,MOQ无法应对或我必须修复我的实现,问题不是模拟?

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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

我对处理器的设置

    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)));
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 14

正如Bruno正确指出的那样,问题是被模拟的StartAsync是同步抛出异常,而不是返回故障任务.

但是,正确的代码无法使用new Task(这将导致挂起,因为任务永远不会启动).相反,使用Task.FromException:

FirstProcessor.Setup(x => x.StartAsync(It.IsAny<TextWriter>())).Returns(
    Task.FromException(new Exception("some exception happened."))
);
Run Code Online (Sandbox Code Playgroud)