Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [SF][Symfony2][Symfony]problem z testowaniem usług / service
szypi1989
post 3.09.2018, 08:23:17
Post #1





Grupa: Zarejestrowani
Postów: 207
Pomógł: 0
Dołączył: 7.09.2010

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


Mam nadzieje, że mnie zrozumiecie. Otóż mam problem z testowaniem service . Te service ma parametry , które są wstrzykiwane . Znów te service składa się 2 następnych service (bo one tam do tego głównego service są wstrzykiwane).
Te 2 następne service znów mają jakieś elementy wstrzykiwane . I irytuje mnie to , że muszę jawnie tak wrzucać paramtery / obiekty, bo w testach nie można wstrzykiwać. Czy istnieje jakiś sposób aby to obejść?
Go to the top of the page
+Quote Post
rad11
post 3.09.2018, 08:28:23
Post #2





Grupa: Zarejestrowani
Postów: 1 270
Pomógł: 184
Dołączył: 7.10.2012
Skąd: Warszawa

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


Nie do końca rozumiem Twój problem ale wydaje mi się, że wystarczy jak użyjesz np:

  1.  
  2. $argument1 = $this->getMockBuilder(Service1::class)
  3. ->disableOriginalConstructor()
  4. ->getMock();
  5.  
  6. $argument2 = $this->getMockBuilder(Service2::class)
  7. ->disableOriginalConstructor()
  8. ->getMock();
  9.  
  10. $argument3 = $this->getMockBuilder(Service3::class)
  11. ->disableOriginalConstructor()
  12. ->getMock();
  13.  
  14. $service = new Service(
  15. $argument1,
  16. $argument2,
  17. $argument3
  18. );
  19.  


chodzi o to abyś po mock`ował sobie wszystkie potrzebne rzeczy
Go to the top of the page
+Quote Post
szypi1989
post 3.09.2018, 09:05:10
Post #3





Grupa: Zarejestrowani
Postów: 207
Pomógł: 0
Dołączył: 7.09.2010

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


No super . Dzięki. A wiesz może jak przetestować funkcję , która używa danych z requesta? Bo wtedy test mi wrzuca błąd ponieważ żadne dane nie są wysyłane?
Nie wiem , czy wiesz o co chodzi .
Mam tutaj dla przykładu kawałek klasy service:
  1. class FetchMsgSql {
  2.  
  3. protected $entityManager;
  4. protected $qb;
  5. protected $parameters;
  6. protected $array_par;
  7. private $requestStack;
  8.  
  9. public function __construct(EntityManager $em, RequestStack $requestStack) {
  10. $this->requestStack = $requestStack;
  11. $this->entityManager = $em;
  12. $this->qb = $em->createQueryBuilder();
  13. }
  14.  
  15. // create results based on data from the request table
  16. // converting data to the form of query
  17. public function getSql() {
  18. $this->qb->select('a')->from('AppBundle:Cars', 'a');
  19. // starts the build_condition function if a query was sent from the searchAction action and the knppaginaton object uses the search function
  20. // search == 1 -> when you view the pages by knppagination and knppagination is supposed to store the results
  21. // search == 1 -> results from the request table are attached during the search engine save in the sortable_link.html view
  22. (($this->requestStack->getCurrentRequest()->query->get('search') == "1") || ($this->requestStack->getCurrentRequest()->getRealMethod() == 'POST') ) ? $this->qb->setParameters($this->build_condition()) : NULL;
  23. $dql = $this->qb->getQuery()->getDQL();
  24. //< convert the dql object to the query form
  25. foreach ($this->qb->getParameters() as $index => $param) {
  26. $dql = str_replace(":" . $param->getName(), $param->getValue(), $dql);
  27. $dql = str_replace("LIKE " . $param->getValue(), "LIKE '" . $param->getValue() . "'", $dql);
  28. }
  29. // >
  30. $query = $this->entityManager->createQuery($dql);
  31. return $query;
  32. }


I Chciałbym przetestować funkcję getSql() . No ale w testach nie mogę, bo nie mam tych danych z requestu. Musiałbym jakoś je ustawić wcześniej .
Go to the top of the page
+Quote Post
rad11
post 3.09.2018, 09:15:09
Post #4





Grupa: Zarejestrowani
Postów: 1 270
Pomógł: 184
Dołączył: 7.10.2012
Skąd: Warszawa

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


Według mnie powinieneś zamockować po prostu tą metodę z odpowiednio zwracanymi danymi które są używane gdzieś dalej, nie widzę sensu abyś miał łączyć się do bazy danych itd aby przetestować Ją samą.

Ale jak chciałbyś utworzyć te parametry to musiałbyś zrobić mniej więcej tak:

  1. $requestStack = new RequestStack();
  2. $requestStack->getCurrentRequest()->setMethod('POST')
  3. $requestStack->getCurrentRequest()->query->set('search', 1);


I to przekazać jako parametr ale tak jak mówię dla mnie testowanie tej metody nie ma sensu

Ten post edytował rad11 3.09.2018, 09:20:30
Go to the top of the page
+Quote Post
nospor
post 3.09.2018, 09:29:36
Post #5





Grupa: Moderatorzy
Postów: 36 440
Pomógł: 6290
Dołączył: 27.12.2004




1) Robiac Mock klasy request mozesz okreslic co maja zwracac dane metody a tym samym mozesz zasymulowac przeslanie parametrow z POST
2) Moim zdaniem masz zle zaprojektowana te klase bo jest ona zalezna od request. Bardziej metoda getSql powinna jako parametr przyjmowac tablice i tam powinienies ustawiac dane z request. Wowczas uniezalezniasz sie od klasu request, twoj service moze dzialac na danych z dowolnego zrodla i bez problemu jestes to w stanie przetestowac

ps:
$dql = str_replace(":" . $param->getName(), $param->getValue(), $dql);
$dql = str_replace("LIKE " . $param->getValue(), "LIKE '" . $param->getValue() . "'", $dql);
Ouch, czemu tak?


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
szypi1989
post 5.09.2018, 08:53:56
Post #6





Grupa: Zarejestrowani
Postów: 207
Pomógł: 0
Dołączył: 7.09.2010

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


Używam knpbundle a on niestety potrzebuje dane trochę bardziej przekowertowane. Zresztą dużo by mówić, po prostu jest coś gdzieś w kodzie kombinowane.
Jeśli tak uważasz, to postaram się to pozmieniać w przyszłości i zmienić trochę model tego. Uważam, że masz racje i źle to zrealizowałem .
Chyba masz racje, nie będę tego testował. Mam słabe doświadczenie w programowaniu i po prostu się uczę testować moją aplikację ;-)

Call to a member function setMethod . Funkcja ta niestety nie działa :-(

Ten post edytował szypi1989 3.09.2018, 09:37:31
Go to the top of the page
+Quote Post
rad11
post 5.09.2018, 10:02:22
Post #7





Grupa: Zarejestrowani
Postów: 1 270
Pomógł: 184
Dołączył: 7.10.2012
Skąd: Warszawa

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


A jaka dokładnie wersja Symfony ?
Go to the top of the page
+Quote Post
szypi1989
post 6.09.2018, 07:24:49
Post #8





Grupa: Zarejestrowani
Postów: 207
Pomógł: 0
Dołączył: 7.09.2010

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


symfony 3.4 . Jakoś nie łapie tego request.Ponieważ jak sprawdzam var_dump($requestStack->getCurrentRequest()) to zwraca mi NULL ale tylko w kodzie testach. A normalnie w kodzie aplikacje zwraca obiekt request. Może coś w kernellu trzeba ustawić?
Go to the top of the page
+Quote Post
rad11
post 6.09.2018, 07:48:47
Post #9





Grupa: Zarejestrowani
Postów: 1 270
Pomógł: 184
Dołączył: 7.10.2012
Skąd: Warszawa

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


To spróbuj zrobić coś takiego:

  1. $request = new Request(['search' => 1],null,null,null,null,['REQUEST_METHOD' => 'POST']);
  2.  
  3. $requestStackMock = $this->getMockBuilder(RequestStack::class)
  4. ->disableOriginalConstructor()
  5. ->getMock();
  6.  
  7. $requestStackMock->expects($this->any())->method('getCurrentRequest')->willReturn($request);
  8.  


i to przekazać jako parametr

Ten post edytował rad11 6.09.2018, 08:32:49
Go to the top of the page
+Quote Post
Crozin
post 6.09.2018, 08:48:52
Post #10





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

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


@rad11 Ale po co tak kombinować?
  1. $request = new Request(...);
  2. $requestStack = new RequestStack();
  3. $requestStack->push($request);
Tak długo jak długo nie trzeba używać żadnych mocków powinno się od nich uciekać. Request / RequestStack to bardzo proste obiekty, które spokojnie można tworzyć sobie na potęgę.

@szypi1989 Tutaj testy dają Ci nawet coś więcej niż pewność, że kod działa. Fakt, że jest Ci je tak trudno napisać ładnie obrazuje to, że kod jest - wybacz za bezpośredniość - słabo napisany. Zadaniem Twojej klasy jest zbudowanie odpowiedniego zapytania SQL/DQL na podstawie jakichś kryteriów. No to w takim razie skup się na tym by robił to i tylko to, korzystając z prostych i specyficznych dla tego problemu (zadania) typów danych.
  1. class AbcSearchCriteria {
  2. private string $name;
  3. private string $value;
  4.  
  5. public __construct(string $name, string $value) { ... }
  6.  
  7. public getName() { return $this->name; }
  8. public getValue() { return $this->value; }
  9. }
  10.  
  11. class AbcSearchQueryBuilder {
  12. public __construct($em, ...)
  13.  
  14. public buildQuery(AbcSearchCriteria $criter) { ... }
  15. }
To że w produkcyjnym kodzie te kryteria będą gdzieś, jakoś budowane na podstawie danych z żądania HTTP nie ma znaczenia dla tej klasy - ona ma się skupić na swoim zadaniu czyli budowaniu odpowiedniego zapytania na podstawie odpowiednich kryteriów. Ten kod strasznie łatwo przetestujesz i co więcej może to być wartościowy test! A co z tą kwestią tworzenia obiektu reprezentującego kryteria? To jest inna część kodu - może być inicjowana gdzieś pewnie na poziomie jakiegoś kontrolera, która powinna być poddana osobnemu testowi - który weryfikuje jedynie czy obiekt kryteriów jest prawidłowo tworzony na podstawie obiektu żądania HTTP.
Go to the top of the page
+Quote Post
szypi1989
post 8.09.2018, 08:45:57
Post #11





Grupa: Zarejestrowani
Postów: 207
Pomógł: 0
Dołączył: 7.09.2010

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


rozumiem o co Tobie chodzi . No ale mam słabe doświadczenie w programowaniu a już sam fakt , że źle zacząłem, że dopiero podchodzę teraz do testów to już z tego wynikają błędy. Teraz sam to widzę
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: 28.03.2024 - 23:01