Pytanie Sprawdź połączenia Received () dla metody asynchronicznej


Po uruchomieniu następującego kodu:

[Test]
public async Task Can_Test_Update()
{
    var response = await _controller.UpdateAsync(Guid.NewGuid());
    response.Valid.Should().BeTrue();

    _commands.Received().UpdateAsync(
        Arg.Is<Something>(
            l => l.Status == Status.Updated)); 
}

Jeśli dodam "await"poprzedzający"_commands.Received().UpdateAsync", generuje wyjątek odwołania o wartości zerowej. Jak mogę to zatrzymać? await niekoniecznie?


14
2018-06-23 07:06


pochodzenie




Odpowiedzi:


Znalazłem odpowiedź tutaj.

Received.InOrder(async () =>
{
    await _Commands.UpdateAsync(Arg.Is<Lobby>(l => l.Status == Status.Updated));
});

14
2018-06-23 08:33



Nie sądzę, że potrzebujesz tego dodatkowego Received() w ramach lambda: Received.InOrder(async () => { await _Commands.UpdateAsync(...); }) - David Tchepak
tak, masz rację, to nie potrzebuje Received (). - letitbe
Podczas uruchamiania testów powoduje błąd: "Oczekuje się, że te połączenia zostaną odebrane w kolejności" - Michael Freidgeim


Kiedy NSubstitute widzi asynchroniczne wywołanie, automatycznie tworzy ono zakończone zadanie, więc oczekuje ono tak, jak można oczekiwać w kodzie (i nie generuje wyjątku NullReferenceException). W takim przypadku to zadanie zostanie zwrócone _commands.UpdateAsync(Status.Updated)) wewnątrz testowanej metody.

The .Received() z drugiej strony sprawdza, czy wywołano metodę asynchroniczną, która jest w pełni synchroniczna, więc nie trzeba jej czekać.

Kluczową rzeczą do zapamiętania jest to, że metody asynchroniczne zwracają a Task. Wywołanie metody asynchronicznej i zwrócenie zadania jest w pełni zsynchronizowane, następnie należy poczekać na Task wiedzieć, kiedy zakończyła się operacja asynchroniczna, którą reprezentuje zadanie.


5
2018-06-24 08:25



wspaniała odpowiedź, wywołanie .Received () nie musi czekać. dzięki, Jake Ginnivan - letitbe


Według ta odpowiedź na Stack Overflow, z NSubstitute wersji 1.8.3 można użyć await i będzie działać zgodnie z oczekiwaniami, zamiast rzucać wyjątek NullReferenceException.

Właśnie wypróbowałem to, ponieważ byłem w wersji 1.5.0 i otrzymałem wyjątek NullReferenceException, jak opisujesz, ale teraz jestem na najnowszym (1.10.0), działa dobrze.


3
2017-07-28 11:41





The Jake Ginnivan odpowiedział poprawnie wskazuje, że dla Received wait nie jest wymagane, jednak kompilator go nie rozumie i pokazuje

ostrzeżenie CS4014: Ponieważ to wywołanie nie jest oczekiwane, wykonanie   bieżąca metoda jest kontynuowana przed zakończeniem połączenia. Rozważać   zastosowanie operatora "oczekującego" na wynik połączenia.

Najprostszym rozwiązaniem jest wyłączenie ostrzeżenia

 #pragma warning disable 4014 //for .Received await is not required, so suppress warning “Consider applying the 'await' operator”
   _publisher.Received(totalNumber).MyMethod(Arg.Any<ParamType>());
 #pragma warning restore 4014

1
2018-01-28 01:15





kiedy dodaję "czekaj" poprzedzające "_commands.Received (). UpdateAsync",   pojawia się błąd o wartości zerowej

To dlatego, że kiedy nie await, metoda (Can_Test_Update) może się zakończyć, zanim faktycznie sprawdzi wartość pustą, którą przechodzisz do metody, co oznacza, że ​​test się kończy. Masz kondycję. Kiedy ty await na UpdateAsync, metoda faktycznie asynchronicznie czeka na zakończenie operacji, oraz UpdateAsync ma szansę uzyskać dostęp do wartości null, którą do niej przechodzisz.

Aby rozwiązać swój błąd, po prostu umieść punkt przerwania wewnątrz UpdateAsync i zobacz, która wartość jest przekazywana jako null do metody. podejrzewam Arg.Is<Something> to Twój problem.


0
2018-06-23 07:16



niż Yuval, dodam "oczekuję _controller.UpdateAsync (Guid.NewGuid ());" w treści. Received () użyte do sprawdzenia, czy uruchomiono _commands.UpdateAsync (), a _commands.UpdateAsync () zwraca tylko zadanie. - letitbe


Jeśli UpdateAsync jest metodą skrótową, musisz zwrócić puste zadanie, a nie puste. Nie możesz czekać na zerowe zadanie.

Przykład:

receivedObject.Stub(s => s.Update(...)).Return(Task.FromResult(0));

Edytować

Problem leży w tym wierszu:

var mockService = Substitute.For<ICalculationServiceAsync>(); 

Lub dokładniej, gdy nazwiesz ją metodą:

await _service.Calculate();

Tworzysz fałszywą usługę, ale nie stosujesz tej metody. Nie jestem pewien, jak to zrobić w Nunit (używamy głównie Rhino, muszę to sprawdzić), ale musisz przeszukać metodę Calculate, aby zwrócić puste zadanie (Task.FromResult (0)). Domyślnie metody skrótowe zwracają domyślny typ zwracany, a domyślny (zadanie) ma wartość null.

O twoje sedno: DoSomethingAsync nie powinno być asynchroniczne. Zakładam, że chciałbyś poczekać na jego wykonanie.


0
2018-06-23 07:22



Mam na myśli gist.github.com/HEskandari/8235481 - letitbe
@letitbe: Zaktualizowano moją odpowiedź. Funkcja DoSomethingAsync nie powinna być asynchroniczna, ponieważ nie możesz już na nią czekać! - Andrew
Próbowałem kpić z metody .Returns (Task.FromResult (false)); ale nadal uzyskać wyjątek odwołania zerowy, gdy wywołanie Received () ;. - letitbe
w SystemUnderTest.DoSomethingAsync spróbuj i zobacz, co _service.Calculate zwraca, zanim zaczekasz. Jeśli jest pusta, to jest problem. - Andrew