Domanda

In gran parte come un follow-up a questa domanda ho fornito con un po 'di codice che funziona se non hanno il compito di attesa, ma non riesce se lo faccio.

Qualcuno può spiegare perché?

Eccezione:

ottengo questo errore quando il codice colpisce il costruttore di una classe di utilità scritto da Stephen Cleary sul suo blog qui

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

Il test (NUnit w / TestDriven.Net corridore):

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

Giusto per essere chiari: Se io commento task.Wait, che prova realmente riesce. Perché?

Punti extra:

So che questo è tecnicamente un'altra questione, ma sembra un peccato di ripetere tutto questo, così:

Perché il mio non MockSynchContext un'eccezione sulla TaskScheduler.FromCurrentSynchronizationContext () nel mio test, ma ha fatto nel secondo compito? Ancora più importante, c'è un modo per passare il contesto lungo in modo da poter fare il test in modo corretto?

È stato utile?

Soluzione

  

"Se io commento task.Wait, quel test ha successo in realtà. Perché?"

Task non riporta le eccezioni che accadono nel compito stesso fino a quando effettivamente esaminare l'attività (sia da 'Wait', 'Valore', 'Eliminare', ecc). E 'quindi genera nuovamente l'eccezione. In una vera e propria applicazione, alla fine il GC avrebbe raggiunto il compito e provocare l'arresto anomalo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top