задача. Ждать исключение - PullRequest
       8

задача. Ждать исключение

2 голосов
/ 08 декабря 2010

В основном как продолжение этого вопроса тестовые асинхронные задачи Я придумал некоторый код, который работает, если у меня нет задачи, ожидающей, но не работает, если я делаю.

Кто-нибудь может объяснить, почему?

Исключение:

Я получаю эту ошибку, когда код попадает в конструктор служебного класса, написанного Стивеном Клири в его блоге здесь

public ProgressReporter()
{
    _scheduler = TaskScheduler.FromCurrentSynchronizationContext();
}

Test 'Smack.Core.Presentation.Tests.Threading.ProgressReporterTests.OnSuccessFullComplete_ExpectedResultIsReturned_JustWait' failed:
System.AggregateException : One or more errors occurred.
----> System.InvalidOperationException : The current SynchronizationContext may not be used as a TaskScheduler.
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
Threading\ProgressReporterTests.cs(142,0): at Smack.Core.Presentation.Tests.Threading.ProgressReporterTests.OnSuccessFullComplete_ExpectedResultIsReturned_JustWait()
--InvalidOperationException
at System.Threading.Tasks.SynchronizationContextTaskScheduler..ctor()
at System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext()
Threading\ProgressReporter.cs(24,0): at Smack.Core.Lib.Threading.ProgressReporter..ctor()
Threading\ProgressReporterTests.cs(52,0): at Smack.Core.Presentation.Tests.Threading.ProgressReporterTests._startBackgroundTask(Boolean causeError)
Threading\ProgressReporterTests.cs(141,0): at Smack.Core.Presentation.Tests.Threading.ProgressReporterTests.<OnSuccessFullComplete_ExpectedResultIsReturned_JustWait>b__a()
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()

Тест (NUnit с TestDriven.Net Runner):

private class MockSynchContext : SynchronizationContext{}

[Test]
public void OnSuccessFullComplete_ExpectedResultIsReturned_Wait()
{
    var mc = new MockSynchContext();
    SynchronizationContext.SetSynchronizationContext(mc);
    Assert.That(SynchronizationContext.Current, Is.EqualTo(mc));
    Assert.DoesNotThrow(() => TaskScheduler.FromCurrentSynchronizationContext());
    var task = Task.Factory.StartNew(() => _startBackgroundTask(false));
    task.Wait(2000);
    _actualResult = 42;
}

СУ:

private void _startBackgroundTask(bool causeError)
{
    _cancellationTokenSource = new CancellationTokenSource();
    var cancellationToken = _cancellationTokenSource.Token;
    _progressReporter = new ProgressReporter();
    var task = Task.Factory.StartNew(() =>
            {
                for (var i = 0; i != 100; ++i) {
                    // Check for cancellation 
                    cancellationToken.ThrowIfCancellationRequested();

                    Thread.Sleep(30); // Do some work. 

                    // Report progress of the work. 
                    _progressReporter.ReportProgress(
                        () =>
                            {
                                // Note: code passed to "ReportProgress" can access UI elements freely. 
                                _currentProgress = i;
                            });
                }

                // After all that work, cause the error if requested.
                if (causeError) {
                    throw new InvalidOperationException("Oops...");
                }


                // The answer, at last! 
                return 42;
            },
        cancellationToken);

    // ProgressReporter can be used to report successful completion,
    //  cancelation, or failure to the UI thread. 
    _progressReporter.RegisterContinuation(task, () =>
    {
        // Update UI to reflect completion.
        _currentProgress = 100;

        // Display results.
        if (task.Exception != null)
            _actualErrorMessage = task.Exception.ToString();
        else if (task.IsCanceled)
            _wasCancelled = true;
        else 
            _actualResult = task.Result;

        // Reset UI.
        _whenCompleted();
    });
}

Просто чтобы прояснить: Если я закомментирую задачу. Подождите, этот тест на самом деле успешен. Почему это так?

Дополнительные очки:

Я знаю, что это технически другой вопрос, но, кажется, стыдно повторять все это, поэтому:

Почему мой MockSynchContext не выдал исключение для TaskScheduler.FromCurrentSynchronizationContext () в моем тесте, но сделал во второй задаче? Что еще более важно, есть ли способ передать контекст, чтобы я мог правильно выполнить тест?

1 Ответ

8 голосов
/ 08 декабря 2010

"Если я закомментирую задачу. Подождите, этот тест на самом деле успешно пройден. Почему это так?"Задача (либо через «Ожидание», «Значение», «Утилизация» и т. д.).Затем он отбрасывает исключение.В реальном приложении GC в конечном итоге достигнет Задачи и приведет к сбою приложения.

...