Czy istnieje sposób na zdefiniowanie różnych pozornych oczekiwań dla różnych argumentów wejściowych? Na przykład mam klasę warstwy bazy danych o nazwie DB. Ta klasa ma metodę o nazwie „Query (string $ query)”, która pobiera ciąg zapytania SQL na wejściu. Czy mogę utworzyć makietę dla tej klasy (DB) i ustawić różne wartości zwracane dla różnych wywołań metod Query, które zależą od wejściowego ciągu zapytania?
117
Odpowiedzi:
Biblioteka PHPUnit Mocking (domyślnie) określa, czy oczekiwanie pasuje wyłącznie na podstawie dopasowania przekazanego do
expects
parametru i ograniczenia przekazanego domethod
. Z tego powodu dwaexpect
wywołania, które różnią się tylko argumentami przekazanymi do,with
zakończą się niepowodzeniem, ponieważ oba będą pasować, ale tylko jedno zostanie sprawdzone jako mające oczekiwane zachowanie. Zobacz przypadek reprodukcji po rzeczywistym przykładzie roboczym.W przypadku problemu należy użyć
->at()
lub->will($this->returnCallback(
zgodnie z opisem wanother question on the subject
.Przykład:
Odtwarza:
Powtórz, dlaczego dwa -> z wywołaniami () nie działają:
Prowadzi do
źródło
$this->anything()
jako jednego z parametrów, aby->logicalOr()
umożliwić podanie wartości domyślnej dla innych argumentów niż ten, który Cię interesuje.Nie jest to idealne rozwiązanie,
at()
jeśli możesz tego uniknąć, ponieważ jak twierdzą ich doktorzyOd 4.1 możesz używać
withConsecutive
np.Jeśli chcesz, aby powracał przy kolejnych połączeniach:
źródło
Fatal error: Call to undefined method PHPUnit_Framework_MockObject_Builder_InvocationMocker::withConsecutive()
, zaktualizowałem do 4.1 w mgnieniu oka z Composerem i działa.willReturnOnConsecutiveCalls
Zabił go.Z tego, co znalazłem, najlepszym sposobem rozwiązania tego problemu jest użycie funkcji mapy wartości PHPUnit.
Przykład z dokumentacji PHPUnit :
Ten test przechodzi pomyślnie. Jak widzisz:
Z tego co wiem, ta funkcja została wprowadzona w PHPUnit 3.6 , więc jest na tyle „stara”, że można ją bezpiecznie używać w prawie każdym środowisku programowania lub przejściowym oraz z dowolnym narzędziem do ciągłej integracji.
źródło
Wygląda na to, że Mockery ( https://github.com/padraic/mockery ) to obsługuje. W moim przypadku chcę sprawdzić, czy w bazie danych są utworzone 2 indeksy:
Kpina, działa:
PHPUnit, to nie działa:
Mockery ma również ładniejszą składnię IMHO. Wygląda na to, że jest odrobinę wolniejszy niż wbudowana funkcja mockowania PHPUnits, ale YMMV.
źródło
Intro
Okay, widzę, że jest jedno rozwiązanie przewidziane dla Mockery, więc nie lubię Mockery, mam zamiar dać ci alternatywę dla Proroctwa, ale proponuję, abyś najpierw przeczytał o różnicy między Mockery a Prophecy.
Krótko mówiąc : „Prophecy używa podejścia zwanego wiązaniem wiadomości - oznacza to, że zachowanie metody nie zmienia się w czasie, ale jest raczej zmieniane przez inną metodę”.
Prawdziwy problematyczny kod do pokrycia
Rozwiązanie PhpUnit Prophecy
Podsumowanie
Po raz kolejny Prophecy jest bardziej niesamowite! Moja sztuczka polega na wykorzystaniu charakteru Proroctwa wiążącego wiadomości i nawet jeśli wygląda to niestety jak typowy, zwrotny kod javascript, zaczynający się od $ self = $ this; ponieważ bardzo rzadko trzeba pisać testy jednostkowe, takie jak ten, myślę, że jest to fajne rozwiązanie i zdecydowanie łatwe do naśladowania, debugowania, ponieważ faktycznie opisuje wykonanie programu.
BTW: Istnieje druga alternatywa, ale wymaga zmiany kodu, który testujemy. Moglibyśmy opakować wichrzycieli i przenieść ich do osobnej klasy:
można opakować jako:
i to wszystko, ale ponieważ nie chciałem tworzyć dla niego kolejnej klasy, wolę pierwszą.
źródło