Dlaczego nie można rozpoznać testów jednostkowych „async void”?

79

async void testów jednostkowych nie można uruchomić w programie Visual Studio 2012:

[TestClass]
public class MyTestClass
{
    [TestMethod]
    public async void InvisibleMyTestMethod()
    {
        await Task.Delay(1000);
        Assert.IsTrue(true);
    }
}

Jeśli chcę mieć asynchroniczny test jednostkowy, metoda testowa musi zwrócić Task:

[TestMethod]
public async Task VisibleMyTestMethod()
{
    await Task.Delay(1000);
    Assert.IsTrue(true);
}

Dlaczego tak się dzieje? Nie to, żebym absolutnie potrzebował async voidmetody testowej, jestem po prostu ciekawy. Program Visual Studio 2012 nie wyświetla żadnego ostrzeżenia ani błędu podczas tworzenia async voidmetody testowej, mimo że nie będzie można jej uruchomić ...

Maks
źródło

Odpowiedzi:

83

async voidmetody należy traktować jako „odpal i zapomnij” - nie ma sposobu, aby czekać na ich zakończenie. Gdyby program Visual Studio miał rozpocząć jeden z tych testów, nie byłby w stanie czekać na zakończenie testu (oznaczać go jako pomyślny) ani przechwytywać zgłoszonych wyjątków.

Za pomocą async Taskwywołującego może czekać na zakończenie wykonywania i przechwytywać wszelkie wyjątki zgłoszone podczas działania.

Zobacz tę odpowiedź dla większej dyskusji async voidvs async Task.

Richard
źródło
3
To nie jest prawda. NUnit obsługuje async voidtesty, a informacje o tym, jak i dlaczego je wspierać, są w pewnym stopniu opisane w tym linku . Zobacz odpowiedź poniżej.
Anupam
21

Dzieje się tak dlatego, że MSTest nie obsługuje async voidtestów jednostkowych. Jest to możliwe , aby to zrobić, wprowadzając kontekst, w którym można je wykonać.

MSTest tego nie obsługuje, prawdopodobnie dlatego, że Microsoft zdecydował, że była to zbyt duża zmiana dla istniejących testów (możliwe, że istniejące testy zablokowałyby się, gdyby nadano im nieoczekiwany kontekst).

Nie ma żadnego ostrzeżenia / błędu kompilatora, ponieważ jest to całkowicie prawidłowy kod C #. Jedynym powodem, dla którego nie działa, jest struktura testów jednostkowych (tj. Uważam, że xUnit obsługuje async voidtesty) i byłoby rażącym naruszeniem oddzielenia obaw dla kompilatora C #, aby spojrzeć na twoje atrybuty, ustalić, używasz MSTest i zdecydujesz, że naprawdę nie chcesz go używać async void.

Stephen Cleary
źródło
1
W pierwszej implementacji (Visual Studio Preview) test zostałby rozpoznany i „uruchomiony”. Problem polegał na tym, że metoda kończyła się za pierwszym oczekiwaniem i taki był wynik testu.
Paulo Morgado
21

W VS2015 stwierdziłem, że żadne metody testowe udekorowane async nie będą wyświetlane w Eksploratorze testów. Skończyło się na usunięciu słowa kluczowego async i zamianie wywołania await w teście na task.Wait () i wykonałem swoje asercje na task.Result.

Wydaje się, że działa dobrze. Nie próbowałem tego jeszcze z testowaniem wyjątków.

var task = TheMethodIWantToTestAsync(someValue);
task.Wait();
var response = task.Result;

Assert.IsNotNull(response);
Assert.IsTrue(response.somevalue);
Nick Wright
źródło
3
Nie myśl, że musi wywołać task.Wait () jako wywołanie task.Result wywoła task.Wait () automatycznie, jeśli zadanie nie zostało zakończone.
stt106