Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Testowanie Observera
Forum PHP.pl > Forum > PHP > Object-oriented programming
Pax95
Witam

Piszę test do testowania obserwatora, jednak coś mi nie chce działać.

  1. <?php
  2.  
  3. namespace Ultilate\GameBundle\QueueSystem;
  4.  
  5. use Ultilate\GameBundle\Listener;
  6.  
  7. abstract class Action implements Listener
  8. {
  9. public $phases = array();
  10. protected $model_name;
  11.  
  12. public function __construct()
  13. {
  14. $this->loadPhases();
  15. }
  16.  
  17. public function notify( $time )
  18. {
  19. /*foreach ( $this->phases as $phase )
  20.   {
  21.   $phase->notify( $time );
  22.   }*/
  23. for ( $i = 0; $i < count( $this->phases ); $i++ )
  24. {
  25. $this->phases[$i]->notify( $time );
  26. }
  27. }
  28.  
  29. protected function loadPhases()
  30. {
  31.  
  32. }
  33. }


  1. <?php
  2.  
  3. namespace Ultilate\GameBundle\QueueSystem;
  4.  
  5. use Ultilate\GameBundle\Listener;
  6.  
  7. abstract class Phase implements Listener
  8. {
  9. public function notify( $time )
  10. {
  11. $this->scenario();
  12. }
  13.  
  14. public function scenario()
  15. {
  16.  
  17. }
  18. }


  1. <?php
  2.  
  3. namespace Ultilate\GameBundle\Tests\QueueSystem;
  4.  
  5. use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
  6.  
  7. class ActionTest extends WebTestCase
  8. {
  9. public function testNotyfingActions()
  10. {
  11. $time = time();
  12.  
  13. $action = $this->getMockForAbstractClass( "Ultilate\GameBundle\QueueSystem\Action" );
  14.  
  15. $phases = array();
  16. for ( $i = 0; $i < 4; $i++ )
  17. {
  18. $phases[$i] = $this->getMockForAbstractClass( "Ultilate\GameBundle\QueueSystem\Phase" );
  19. $phases[$i]->expects( $this->once() )
  20. ->method( "notify" )
  21. ->with( $this->equalTo( $time ) );
  22. }
  23.  
  24. $reflector = new \ReflectionProperty( 'Ultilate\GameBundle\QueueSystem\Action', 'phases' );
  25. $reflector->setAccessible( true );
  26. $reflector->setValue( $action, $phases );
  27.  
  28. $action->notify( $time );
  29. }


Pierwszy kod to testowana klasa, drugi to zależny obiekt, a trzecia to test jednostkowy.
Po odpaleniu testu wyskakuje błąd:
Kod
There was 1 failure:

1) Ultilate\GameBundle\Tests\QueueSystem\ActionTest::testNotyfingActions
Expectation failed for method name is equal to <string:notify> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.
destroyerr
Skoro testujesz klase Action to nie mozesz testowac jej mocka tylko instancje tej klasy.
Pax95
Mock klasy Phase miał być tylko pustym obiektem, ktory ocenia, czy został poinformowany (została przeciążona metoda notify()), jednak nie potrafiłem zrobić atrapy pustego obiektu.

Mimo to nadal nie rozumiem, czemu kod nie przechodzi testu.
destroyerr
Bo nie testujesz klasy Action tylko jej mocka wynika z tego, że nie wykonujesz kodu zawartego w Action::notify.
Pax95
Ale Action jest klasą abstrakcyjną.

Dla przykładu poniższy test przechodzi pomyślnie.

  1. public function testAddingMoreActionsThanLimit()
  2. {
  3. $this->setExpectedException( "Ultilate\GameBundle\QueueSystem\FullQueueException" );
  4.  
  5. $queue = $this->getMockForAbstractClass( "Ultilate\GameBundle\QueueSystem\Queue" );
  6. $queue->setLength( 10 );
  7.  
  8. $this->addActionsAndGetArrayOfThem( $queue, 15 );
  9. }
-=Peter=-
Cytat
Ale Action jest klasą abstrakcyjną.

To utwórz jej testową klasę konkretną, mocki nie służą do tego.

  1. //zamień
  2. $phases[$i] = $this->getMockForAbstractClass( "Ultilate\GameBundle\QueueSystem\Phase" );
  3. //na
  4. $phases[$i] = $this->getMockBuilder( "Ultilate\GameBundle\QueueSystem\Phase" )->setMethods(array('notify'))->getMock();
destroyerr
Dobra, niedokładnie przeczytałem kod i trochę zamieszałem za co przepraszam.
Skoro Action jest klasą abstrakcyjną to oprócz Twojego sposobu są jeszcze dwa inne: tworzysz klasę rozszerzającą tylko na potrzeby testów (która nie jest abstrakcyjna) albo testujesz tylko klasy które dziedziczą po abstrakcyjnej.

Rozwiązanie Twojego problemu podał Ci Peter.
Pax95
Rozumiem, że ten kod co podał Peter to pusty Mock z jedną metodą notify()?
-=Peter=-
Nie wiem co rozumiesz pod pojęciem "pusty Mock". Jeśli nie mockujesz interfejsu to musisz jawnie przekazać nazwy metod które mają być mockowane. Dotyczy to też metod abstrakcyjnych, czyli twój kod: $this->getMockForAbstractClass( "Ultilate\GameBundle\QueueSystem\Phase" ) zadziałałby gdyby metoda notify była abstrakcyjna.
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.