2014-05-01 33 views
24

Przygotowuję niektóre testy jednostkowe i za pomocą Rhino Mocks do wypełnienia testowanego obiektu. Jedną z rzeczy, które są wyśmiewane, jest Task<HttpResponseMessage>, ponieważ testowana logika obejmuje wywołanie do HttpClient, aby uzyskać odpowiedź asynchroniczną.Jak wyśmiać zadanie <> Wynik?

Więc zacząłem ustanowienia mocks jak to:

var httpClient = MockRepository.GenerateMock<HttpClient>(); 
var taskFunc = MockRepository.GenerateMock<Func<HttpResponseMessage>>(); 
var responseTask = MockRepository.GenerateMock<Task<HttpResponseMessage>>(taskFunc); 
var response = MockRepository.GenerateMock<HttpResponseMessage>(); 

httpClient.Stub(c => c.PostAsJsonAsync<IEnumerable<LogMessage>>(Arg<string>.Is.Anything, Arg<IEnumerable<LogMessage>>.Is.Anything)).Return(responseTask); 
responseTask.Stub(t => t.Result).Return(response); 
response.Stub(r => r.IsSuccessStatusCode).Return(true); 

(„Ustawa” krok testu będzie instancję obiektu badanego, paszy mu httpClient i uruchomić metodę . na to „dochodzić” zweryfikuje poprzez mocks że oczekiwane wywołania metod dokonano na nich)

Krocząc przez to w debugger, jest nieokreślony zawiesić na tej linii.

responseTask.Stub(t => t.Result).Return(response); 

Nie mam dużego doświadczenia z Rhino Mocks lub z asynchronizacją C#, więc mogę przeoczyć coś oczywistego. Celem jest oczywiście, aby każde połączenie z właściwością .Result zwróciło próbę response. Ale wygląda na to, że moja próba sama w sobie może wywołać .Result, czego oczekiwałbym w nieskończoność, skoro jest to tylko udawanie?

Jaki jest właściwy sposób aranżacji? Zasadniczo muszę dostarczyć mój obiekt z wyszydzanym HttpClient i potwierdzić, że metoda została wywołana na nim z określonym argumentem.

+1

Zrobiłem dużo szyderstwa wokół zadań około roku temu przy użyciu MOQ. O ile się nie mylę, wystarczy zastąpić komunikat taskFunc, który przechodzisz, do swojej fałszywej odpowiedzi. Następnie ta funkcja próbna natychmiast zwróci odpowiedź. – Keith

+0

@Keith: Interesujące. Więc po prostu stwórz prawdziwe 'Func ' zamiast makiety, która tylko zwraca? Po prostu próbowałem jako takie: 'Func taskFunc = delegate() {return response; }; 'i przekazane, że' taskFunc' na próbę 'responseTask', ale zachowuje się to samo zachowanie. – David

+1

Nie sądzę, że potrzebujesz rzeczywistego zadania próbnego. To, czego potrzebujesz do makiety, to funkcja przekazywana do zadania, więc po prostu zwróci "x". – Keith

Odpowiedz

37

Najprostszą rzeczą jest to, aby powrócić wypełnionego zadania z oczekiwanego rezultatu:

var responseTask = Task.FromResult(response); 

sobie wyobrazić powód tego jest taki, że wisi szydzili zadaniem nie jest uruchamiany, a więc dana func nie jest prowadzony. Można go uruchomić w teście:

var responseTask = MockRepository.GenerateMock<Task<HttpResponseMessage>>(taskFunc); 
responseTask.Start(); 

Jednak nie ma powodu, aby drwić zadania, ponieważ łatwo mogą tworzyć bezpośrednio zakończone/zawiodły/anulowania zadania.

+0

Wygląda na to, że to działa. Z tym również musiałem usunąć przez ostatnie dwa wywołania 'Stub() '. ('.Result' jest obsługiwany przez twoją odpowiedź,' .IsSuccessStatusCode' rzucił błąd podczas próby jego pobrania, ale wydaje się domyślnie "prawda" w fałszywym stanie.) Dzięki! – David

+0

Dzięki, to też mi pomogło! – Aaron

Powiązane problemy