Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> PHPUnit Mock
Turson
post 20.12.2016, 12:06:34
Post #1





Grupa: Zarejestrowani
Postów: 4 291
Pomógł: 829
Dołączył: 14.02.2009
Skąd: łódź

Ostrzeżenie: (0%)
-----


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()
Go to the top of the page
+Quote Post
vokiel
post 21.12.2016, 10:36:40
Post #2





Grupa: Zarejestrowani
Postów: 2 592
Pomógł: 445
Dołączył: 12.03.2007

Ostrzeżenie: (0%)
-----


Tak, możesz https://phpunit.de/manual/current/en/test-doubles.html


--------------------
Go to the top of the page
+Quote Post
Turson
post 21.12.2016, 11:39:58
Post #3





Grupa: Zarejestrowani
Postów: 4 291
Pomógł: 829
Dołączył: 14.02.2009
Skąd: łódź

Ostrzeżenie: (0%)
-----


  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

Ten post edytował Turson 21.12.2016, 11:43:12
Go to the top of the page
+Quote Post
lukaskolista
post 21.12.2016, 14:36:36
Post #4





Grupa: Zarejestrowani
Postów: 872
Pomógł: 94
Dołączył: 31.03.2010

Ostrzeżenie: (0%)
-----


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/

Ten post edytował lukaskolista 21.12.2016, 14:42:15
Go to the top of the page
+Quote Post
Crozin
post 21.12.2016, 14:44:13
Post #5





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


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.

Ten post edytował Crozin 21.12.2016, 14:44:33
Go to the top of the page
+Quote Post
Turson
post 21.12.2016, 14:59:18
Post #6





Grupa: Zarejestrowani
Postów: 4 291
Pomógł: 829
Dołączył: 14.02.2009
Skąd: łódź

Ostrzeżenie: (0%)
-----


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ć
Go to the top of the page
+Quote Post
Crozin
post 21.12.2016, 17:37:49
Post #7





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
Turson
post 22.12.2016, 08:51:16
Post #8





Grupa: Zarejestrowani
Postów: 4 291
Pomógł: 829
Dołączył: 14.02.2009
Skąd: łódź

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
lukaskolista
post 22.12.2016, 12:28:54
Post #9





Grupa: Zarejestrowani
Postów: 872
Pomógł: 94
Dołączył: 31.03.2010

Ostrzeżenie: (0%)
-----


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.

Ten post edytował lukaskolista 22.12.2016, 12:30:56
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 29.03.2024 - 09:10