Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]refaktoryzacja pod testy jednostkowe. co z tą klasą jest nie tak?
Forum PHP.pl > Forum > Przedszkole
porzeczki
zamierzam pisać pierwsze testy jednostkowe i otworzyłem pierwszą klasę do testowania :


(klasa jest bez sensu bo ją przeredagowałem by nie skupiać się na zagnieżdżonych elsach itp, a skupić się na strukturze klasy, że jedna metoda wywołuje 3 inne, i że te metody nic nie zwracają tylko przypisują wartość właściwościom klasy))
  1. class Order
  2. {
  3. private $em;
  4. private $orders;
  5. private $tableDetails;
  6. private $forms;
  7.  
  8. function __construct(EntityManager $em)
  9. {
  10. $this->em = $em;
  11. }
  12.  
  13. public function prepareOrder($tableDetails, $tmpForms)
  14. {
  15. $this->setFields($tableDetails, $tmpForms);
  16.  
  17. $this->setFalse();
  18. $this->setFilter();
  19.  
  20. $this->prepareRepository();
  21. }
  22.  
  23. private function setFields(array $fields, array $forms)
  24. {
  25. $this->tableDetails = $fields;
  26. $this->forms = $forms;
  27. }
  28.  
  29. private function setFalse()
  30. {
  31. if ($this->isAnyFormValid()){
  32. $this->tableDetails['filterField'] = false;
  33. }
  34. }
  35.  
  36. private function setFilter()
  37. {
  38. if(!($this->tableDetails['filter']))
  39. {
  40. $this->prepareFilterValue();
  41. }
  42.  
  43. }
  44.  
  45. private function prepareFilterValue(){
  46. if(!($this->tableDetails['filterField'])){
  47. $this->tableDetails['filter'] = 'all';}
  48. }
  49.  
  50.  
  51.  
  52. private function isAnyFormValid()
  53. {
  54. if(($this->forms['StatusForm']->isValid())
  55. {
  56. return 1;
  57. }
  58. }
  59.  
  60. private function prepareRepository()
  61. {
  62. if($this->tableDetails['filter'] == 'all'){
  63. $this->orderRepositoryMaker();
  64. }
  65.  
  66.  
  67. private function orderRepositoryMaker()
  68. {
  69. $this->orders = $this->em->getRepository('AppBundle:Zamowienie')
  70. ->findAll(..)
  71. if (!$this->orders) {throw new \Exception('Nie można znaleźć zamówień');}
  72. }
  73.  
  74.  
  75.  
  76. public function getTableDetails()
  77. {
  78. return $this->tableDetails;
  79. }
  80.  
  81. public function getOrder()
  82. {
  83. return $this->orders;
  84. }
  85. }


także mam 3 metody publiczne:
- prepareOrder
- getTableDetails
- getOrder


jak mam np testować metodę prepareOrder() która nic nie zwraca, wywołuje kilka metod prywatnych, które przypisują wartości właściwościom klasy? Albo jak zmodyfikowac klasę by była test-friendly?
nospor
Troche nie na temat, ale dobrze by ta metoda:
  1. private function isAnyFormValid()
  2. {
  3. if(($this->forms['StatusForm']->isValid())or
  4. ($this->forms['DataZamForm']->isValid())or
  5. ($this->forms['NrKlientaForm']->isValid()))
  6. {
  7. return 1;
  8. }
  9. }


Wygladala tak:
  1. private function isAnyFormValid()
  2. {
  3. if(($this->forms['StatusForm']->isValid())or
  4. ($this->forms['DataZamForm']->isValid())or
  5. ($this->forms['NrKlientaForm']->isValid()))
  6. {
  7. return true;
  8. }
  9.  
  10. return false;
  11.  
  12. }


lub krocej:
  1. private function isAnyFormValid()
  2. {
  3. return $this->forms['StatusForm']->isValid() ||
  4. $this->forms['DataZamForm']->isValid() ||
  5. $this->forms['NrKlientaForm']->isValid();
  6.  
  7. }


Czyli jesli metoda zwraca wynik logiczny to ma zwracac wynik logiczny a nie 1 czy nic.
com
dla przykładu z :
http://forum.php.pl/index.php?showtopic=253330

no to przetestować czy ustawia to prosto sprawdzasz czy zostało ustawione zwracając sobie geter i czy instancja jest ok, a co do reszty to dlaczego ta metoda robi magie, polecałbym zapoznać się z zasadami SOLID, a problem rozwiążę się sam. W skrócie ta metoda nie powinna robić wszystkiego, seter nie ma logiki.
porzeczki
dzięki. (cholernie ciężko mi idzie decydowanie czym jest JEDNA ODPOWIEDZIALNOŚĆ klasy, no bo to zależy z jakiego poziomu spojrzeć na klasę. Klasa może być odpowiedzialna za zwrócenie repozytorium, ale po drodze robi też parę dupereli, no i ciężko mi roztrzygać czy każdy duperel ma być osobną klasą czy prywatną metodą. Czy jeśli duperel ma 40 linijek kodu to już ma być osobną klasą mimo że tak naprawdę nie robi nic ważniejszego niż inny duperel z 3 linijkami kodu)

Cytat(com @ 9.12.2016, 00:22:48 ) *

link nie działa.
com
Tam pod tym linkiem był ten Twój drugi przykład z kodem, ale moderator zamknął temat, ok ale czemu upychasz to w metody prywatne? zrób tak żeby każdy kto jej użyje wiedział co się tam dzieje, wtedy tez będzie łatwiej to przetestować, jak wyciągniesz to co masz zrobić na zewnątrz i z tamtego poziomu to wywołasz.
porzeczki
czyli masa publicznych pierdół wywoływana w kontrolerze. Specjalnie chowałem to w prywatnych bo każą chude kontrolery robić.
com
mogą być prywatne metody, ale musisz tak zaprojektować żeby jak ktoś weźmie Twój kod wiedział co się tam stanie jak go wykona, dlatego są ważne testy, bo one dokumentują na bieżąco Twój kod, skoro kod nie jest testowany, to znaczy, ze trzeba go przebudować tak, żeby dało się go przetestować smile.gif

Osobiście wydzieliłbym Encje, czy repozytorium czy co to tam masz od reszty logiki smile.gif
porzeczki
Cytat(com)
ok ale czemu upychasz to w metody prywatne? zrób tak żeby każdy kto jej użyje wiedział co się tam dzieje, wtedy tez będzie łatwiej to przetestować, jak wyciągniesz to co masz zrobić na zewnątrz i z tamtego poziomu to wywołasz.

Cytat(com)
musisz tak zaprojektować żeby jak ktoś weźmie Twój kod wiedział co się tam stanie jak go wykona

Ta klasa jest paskudna, ale jej publiczne metody są jasne.

Na moje oko w kontrolerze wygląda to dość czytelnie:
  1. $manager_order = $this->get('app.manager_order');
  2. $manager_order->prepareOrder($tableDetails, $tmpForms);
  3. $orders = $manager_order->getOrder();
  4. $tableDetails = $manager_order->getTableDetails();


Mam opory przed wyprowadzaniem kodu prywatnych metod do nowych klas, który
- jest bardzo silnie związany z właściwościami klasy.
- jest specyficzny, jednorazowego użytku. Tak jak metoda prepareRepository() przeniesiona do osobnej klasy i tak nigdy drugi raz użyta nie będzie.

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.