Stiamo scrivendo unit test per codice asincrono usando MSTest e Moq.Mocking Async Methods
Così abbiamo un codice che sembra qualcosa di simile:
var moq = new Mock<Foo>();
moq.Setup(m => m.GetAsync())
.Returns(Task.FromResult(10));
O come questo su progetti che hanno una versione più recente di Moq
var moq = new Mock<Foo>();
moq.Setup(m => m.GetAsync())
.ReturnsAsync(10);
Guardando l'attuazione Moq di ReturnsAsync:
public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(this IReturns<TMock, Task<TResult>> mock, TResult value) where TMock : class
{
TaskCompletionSource<TResult> completionSource = new TaskCompletionSource<TResult>();
completionSource.SetResult(value);
return mock.Returns(completionSource.Task);
}
Entrambi i metodi sembrano essere gli stessi sotto il cofano. Entrambi creano TaskCompletionSource
, chiamano SetResult
e restituiscono il Task
Fin qui tutto bene.
Ma i metodi corti in esecuzione async
sono ottimizzati per agire in modo sincrono. Ciò sembra implicare che TaskCompletionSource
sia sempre sincrono, il che sembrerebbe anche suggerire che la gestione del contesto e eventuali problemi correlati che potrebbero verificarsi non si verifichino mai.
Quindi, se abbiamo avuto qualche codice che stava facendo alcuni async
no-no, come la miscelazione awaits
, Wait()
e Result
, che questi problemi non sarebbero rilevati nel test di unità.
Potrebbe esserci qualche vantaggio nel creare un metodo di estensione che fornisce sempre il controllo? Qualcosa di simile:
public async Task<T> ReturnsYieldingAsync<T>(T result)
{
await Task.Yield();
return result;
}
In questo caso avremmo un metodo che è garantito per eseguire in modo asincrono.
Il vantaggio percepito potrebbe rilevare un codice asincrono errato. Ad esempio, potrebbe catturare qualsiasi deadlocking o eccezione durante la deglutizione durante il test dell'unità.
Non sono sicuro al 100% che sia così, quindi sarei davvero interessato a sentire ciò che la comunità ha da dire.
Direi andare per 'ReturnsYieldingAsync', ma ancor più, per sperimentare potenziali deadlock, è necessario installare un contesto di sincronizzazione nei test runner, qualcosa come [' AsyncPump'] (http: // blogs. msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx). – Noseratio
Penso che dovresti provare a scrivere un test che dimostra 1. funzionerà come previsto e 2. puoi creare un caso di test che segue esattamente il caso di test da 1 ma non chiama mai 'ReturnsYieldingAsync' e fallisce. –
@Noseratio Bella scoperta su 'AsyncPump'. Il problema principale che ritengo di riscontrare è che il test in esecuzione è che il contesto di sincronizzazione del test runner è nullo. Scambiare il 'AsyncPump' sembra essere la strada da percorrere, come mostrato qui http: // StackOverflow.it/questions/14087257/how-to-add-synchronization-contest-to-async-test-method – swestner