Piszemy testy jednostkowe dla kodu asynchronicznego przy użyciu MSTest i Moq.Makiety metod asynchronicznych
Mamy więc jakiś kod, który wygląda mniej więcej tak:
var moq = new Mock<Foo>();
moq.Setup(m => m.GetAsync())
.Returns(Task.FromResult(10));
Albo jak to się na projektach, które mają nowszą wersję Min
var moq = new Mock<Foo>();
moq.Setup(m => m.GetAsync())
.ReturnsAsync(10);
Patrząc na realizację Min z 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);
}
Obie metody wydają się być takie same pod maską. Oba tworzą TaskCompletionSource
, wywołują SetResult
i zwracają wartość Task
Do tej pory tak dobrze.
Ale krótko pracujące metody async
są zoptymalizowane do działania synchronicznego. Wydaje się to sugerować, że TaskCompletionSource
jest zawsze synchroniczna, co również sugerowałoby, że obsługa kontekstu i wszelkie związane z tym problemy, które mogą wystąpić, nigdy nie miałyby miejsca.
Więc gdybyśmy mieli jakiś kod, który robił jakieś async
nie-nie, podobnie jak mieszanie awaits
, Wait()
i Result
, że problemy te nie zostaną wykryte podczas testów jednostkowych.
Czy istniała jakaś korzyść w tworzeniu metody rozszerzenia, która zawsze daje kontrolę? Coś takiego:
public async Task<T> ReturnsYieldingAsync<T>(T result)
{
await Task.Yield();
return result;
}
W tym przypadku mamy metodę, która jest gwarantowana do wykonywania asynchronicznie.
Dostrzeganą zaletą byłoby wykrycie złego asynchronicznego kodu. Na przykład może złapać wszelkie zakleszczenia lub przypadkowe połknięcie podczas testowania jednostkowego.
Nie jestem w 100% pewien, że tak jest, więc naprawdę chciałbym usłyszeć, co społeczność ma do powiedzenia.
Powiedziałbym, idź na "ReturnsYieldingAsync", ale jeszcze bardziej, aby doświadczyć potencjalnych zakleszczeń, które trzeba zainstalować kontekst synchronizacji w testowych biegaczy, coś jak ['AsyncPump'] (http: // blogs. msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx). – Noseratio
Myślę, że powinieneś spróbować napisać przypadek testowy, który udowodni, że 1. będzie działał zgodnie z oczekiwaniami i 2. możesz utworzyć case test, który następuje po przypadku testowym od 1 dokładnie, ale nigdy nie wywołuje 'ReturnsYieldingAsync' i kończy się niepowodzeniem. –
@Noseratio Ładne znalezisko na 'AsyncPump'. Główny problem, o którym myślę, że napotykamy, polega na tym, że test uruchamia się w taki sposób, że kontekst synchronizacji testera jest zerowy. Zamiana 'AsyncPump' wydaje się być sposobem na przejście, jak pokazano tutaj: http: // stackoverflow.com/questions/14087257/how-to-add-synchronization-context-to-async-test-method – swestner