Frage

Weitgehend als Follow-up auf diese Frage Test Driven asynch Aufgaben Ich habe kommen mit einigem Code, das funktioniert, wenn ich nicht die Aufgabe warten müssen, aber nicht, wenn ich es tue.

Kann mir jemand erklären, warum?

Ausnahme:

Ich bekomme diese Fehlermeldung, wenn der Code den Konstruktor einer Utility-Klasse trifft geschrieben von Stephen Cleary auf seinem Blog hier

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()

Der Test (NUnit w / TestDriven.Net Läufer):

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;
}

SUT:

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();
    });
}

Just klar zu sein: Wenn ich Kommentar aus task.Wait, dass Test tatsächlich gelingt. Warum das?

Zusätzliche Punkte:

Ich weiß, dass dies technisch eine andere Frage, aber es scheint eine Schande, dies alles zu wiederholen, so:

Warum hat meine MockSynchContext keine Ausnahme auf TaskScheduler.FromCurrentSynchronizationContext () in meinem Test werfen, aber in der zweiten Aufgabe gemacht hat? Noch wichtiger ist, gibt es einen Weg entlang, den Kontext zu passieren, damit ich richtig den Test tun?

War es hilfreich?

Lösung

"Wenn ich task.Wait Kommentar aus, dass Test erfolgreich ist tatsächlich. Warum ist das?"

Task keine Ausnahmen berichten, die in der Task passiert selbst, bis Sie tatsächlich die Aufgabe (entweder durch ‚Warte‘, ‚Wert‘, ‚Entsorgen‘, usw.) untersuchen. Es rethrows dann die Ausnahme. In einer realen Anwendung, schließlich würde die GC die Aufgabe erreichen und führen Sie Ihre App zum Absturz bringen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top