Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: PHPUnit Mock
Forum PHP.pl > Forum > PHP
Turson
Mam klasę
  1. class Foo{
  2.  
  3. public function a(){
  4. return $this->b() || $this->c();
  5. }
  6.  
  7. protected function b(){
  8. return time()%2 === 0;
  9. }
  10.  
  11. protected function c(){
  12. return time()%3 === 0;
  13. }
  14.  
  15. }

czy możliwe jest przetestowanie a() poprzez zamockowanie b() oraz c()?
Typu:
mockuję b() że zwraca true i wtedy spodziewam się w a() assertTrue()
mockuję c() że zwraca true i wtedy spodziewam się w a() assertTrue()
mockuję b() oraz c() że zwracają false i spodziewam się w a() assertFalse()
mockuję b() oraz c() że zwracają true i spodziewam się w a() assertTrue()
vokiel
Tak, możesz https://phpunit.de/manual/current/en/test-doubles.html
Turson
  1. class Foo{
  2.  
  3. public function a(){
  4. return $this->b() || $this->c();
  5. }
  6.  
  7. protected function b(){
  8. return false;
  9. }
  10.  
  11. protected function c(){
  12. return false;
  13. }
  14.  
  15. }

  1. public function testFoo(){
  2. $mock = $this->createMock(Foo::class);
  3. $mock->method('b')->willReturn(true);
  4. $this->assertTrue($mock->a());
  5. }

efekt
Cytat
Trying to configure method "b" which cannot be configured because it does not exist, has not been specified, is final, or is static


natomiast, kiedy b() będzie publiczne, to
Cytat
Failed asserting that null is true.


//edit
chyba że tak?
  1. $mock = $this->getMockBuilder(Foo::class)->setMethods(['b'])->getMock();
  2. $mock->method('b')->willReturn(true);
  3. $this->assertTrue($mock->a());

teraz już na zielono smile.gif
lukaskolista
Nie należy mockować testowanej jednostki. W testach jednostkowych mockujesz wszystko poza testowaną jednostką.

Takie podejście uniemożliwia jakąkolwiek refaktoryzacje bez ruszania testów, a wnętrze klasy powinny być pod tym względem elastyczne (czyt. zmiany w implementacji nie powinny powodować wysypywania się testów).
Dodatkowo w takim przypadku Twoje testy są bez sensu, lepiej w ogóle ich nie pisać.

Zobacz tutaj: https://www.schmengler-se.de/en/2011/03/php...-in-unit-tests/
Crozin
Czy mógłbyś opisać jaki masz konkretny przypadek? Wygląda to trochę tak jakbyś próbował od złej strony podejść do testów. Przede wszystkim jeżeli metody b() i c() są niepubliczne nie powinny być w ogóle ujmowane w testach - są szczegółem implementacyjnym.
Turson
Podam przykład. Przypuśćmy, że
a() -> zwraca % postępu jakiejś operacji. Żeby wyliczyć % korzysta z b() -> ile czasu operacja zajmie, c() -> ile czasu uplynelo.
Myślę, że to spoko przykład.
Chcę napisać testy, czy dla konkretnych b() i c() wynik a() będzie taki jak powinien być
Crozin
To sugeruje, że albo powinieneś mieć - w zależności od stopnia złożoności - prostą funkcję/metodę, która przyjmuje w postaci argumentów te dwie wartości (a nie wyciąga je samodzielnie) albo powinna operować na obiekcie innej klasy, który te dane zwraca - a taki już łatwo podmienić czy to dedykowaną dla testów, "śmieciową" implementacją czy właśnie jakimś mockiem.

Jeżeli powyższe dalej nie jest rozwiązaniem Twojego problemu opisz jak dokładnie wygląda Twoja sytuacja - problemy z testami są najczęściej spowodowane złym zaprojektowaniem systemu.
Turson
Pomińmy to, że ta funkcja powinna przyjmować parametry. Przyjmijmy to jak jest, bo odzwierciedla mój problem. Mam helper, który zawiera podobne funkcje jak podane wyżej. Helper jest specyficzny dla danego problemu, dlatego funkcja nie przyjmuje parametrów.W widoku chcę tylko echo $helper->a() i mnie nie obchodzi, co a() robi, ani nie chcę mu dawać parametrów.
lukaskolista
I tu dochodzimy do sedna. Testy wspierają dobrą architekturę, której w Twoim rozwiązaniu brak.

Prosta zasada: jak testy są trudne w napisaniu, to coś jest nie tak. Dodatkowo sugeruję stosować TDD, pozbedziesz się takich problemów. Genrealnie z helperami i wszystkim, co statyczne jest problem.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.