Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHPUnit] Testowanie metody, która ma referencję
Forum PHP.pl > Forum > PHP
wujek2009
Hej,

Mam sytuację, w której jest metoda a jeden z jej argumentów idzie przez referencję. Mój problem polega na tym, że ta referencja zwraca IDki, które później są sprawdzane w innej metodzie (tej, która wywołała) czy IDki są w tablicy, jeśli tak to zwróć true. Poniżej przedstawiam schemat (nazwy klas, metod - zmyślone na potrzeby tematu, flow jest jednak ten sam):

  1. <?php
  2.  
  3. class Db
  4. {
  5. public function update($rows, &$success, &$error)
  6. {
  7. if ((..)) {
  8. $success[] = $this->getId();
  9. } else {
  10. $error[] = $this->getId();
  11. }
  12. }
  13. }
  14.  
  15. class Prepare
  16. {
  17. protected $db;
  18.  
  19. public function setDb($db)
  20. {
  21. // itd.
  22. }
  23.  
  24. public function make()
  25. {
  26. // $rows = (...) jakaś tam obróbka danych
  27. $success = array();
  28. $error = array();
  29.  
  30. $this->db->update($rows, $success, $error);
  31.  
  32. return ((count($success) > 0 AND count($error) == 0) ? true : false);
  33. }
  34. }
  35.  
  36. class TestPrepare extends PHPUnit_Framework_TestCas
  37. {
  38. public function testMakeMethod()
  39. {
  40. $mck = Mockery::mock();
  41. $mck->shouldReceive('update')
  42. ->with(
  43. ['id' => 51, 'name' => 'John', 'password' => 'Hour']
  44. // REFERENCE?
  45. // REFERENCE?
  46. )
  47. ->once()
  48. ->andReturn(true)
  49.  
  50. $prepare = new Prepare();
  51. $prepare->setDb($mck);
  52. $response = $prepare->make();
  53.  
  54. $this->assertTrue($response)
  55. }
  56. }


I teraz dla #44, #45 linijki nie wiem co mam wstawić, aby metoda, którą mockuje przekazywała w sobie też referencję z testowymi danymi, próbowałem coś w stylu:
  1. ->with(
  2. ['id' => 51, 'name' => 'John', 'password' => 'Hour']
  3. \Mockery::on(function(&$error) {
  4. $error = array();
  5.  
  6. return true;
  7. }),
  8. \Mockery::on(function(&$success) {
  9. $success[] = 51;
  10.  
  11. return true;
  12. }),
  13. )


ale to nie działa, ponieważ jak zrobię sobie:
  1. var_dump($success, $errors)


przed tym return w klasie: Prepare to cały czas mam pustą tablice - w ogóle nie dodało mojego "51" (jako ID) w konsekwencji mam, że test nie przeszedł. Ma ktoś jakiś pomysł?
lukaskolista
Stworzyłeś idealny przykład na to, dlaczego nie należy używać referencji (nie mówię o obiektach, które mają referencje tworzone przez mechanizm języka).

http://docs.mockery.io/en/latest/reference...behaviours.html
  1. <?php
  2.  
  3. $m->shouldReceive('insert')->with(
  4. \Mockery::on(function(&$data) {
  5. if (!is_array($data)) return false;
  6. $data['_id'] = 123;
  7. return true;
  8. }),
  9. \Mockery::any()
  10. );


Nie znam mockery, ale być może linijka
if (!is_array($data)) return false;
jest jednak istotna (php to bardzo magiczny język z wieloma magicznie działającymi bibliotekami smile.gif).
skowron-line
@wujek2009 teoria jak i praktyka mówi że jeżeli masz problem z przetestowaniem kodu to najprawdopodobniej napisałeś go źle. Na twoim miejscu nie tracił bym czasu na szukanie rozwiązania odnośnie testowania a skupił się na przemyśleniu kodu który napisałeś

  1. class Db
  2. {
  3. public function update($rows, &$success, &$error)
  4. {
  5. if ((..)) {
  6. $this->success[] = $this->getId();
  7. } else {
  8. $this->errored[] = $this->getId();
  9. }
  10. }
  11.  
  12. public function getSuccessfullyProcessed()
  13. {
  14. return $this->success;
  15. }
  16.  
  17. public function getErrored()
  18. {
  19. return $this->errored;
  20. }
  21. }
wujek2009
Dzięki Panowie za odpowiedź. Jeśli chodzi o samą prezentację kodu to wygląda to tak, że do istniejącego rozwiązania muszę dopisać testy.
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.