Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ Frameworki _ [Symfony] Testowanie aplikacji

Napisany przez: Malinaa 6.09.2023, 13:14:38

Cześć,
chciałbym wykonać testowanie rejestracji i logowania w Symfony.

Symfony -> w katalogu tests/Controller/ utworzyłem plik SecurityControllerTest.php (test logowania),
gdzie chciałbym uzupełnic formularz danymi i zalogować użytkownika, następnie sprawdzić, czy jest zalogowany.

Napisałem taki kod, ale ciągle sypie errorami (coś tu rzeźbię)?

  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. namespace App\Tests\Controller;
  6.  
  7. use App\Repository\UserRepository;
  8. use App\Tests\Integration\AbstractIntegrationWebTestCase;
  9.  
  10. class SecurityControllerTest extends AbstractIntegrationWebTestCase
  11. {
  12. public const TEST_USER_LOGIN = 'test@domain.com';
  13. public const TEST_USER_PASSWORD = 'test123';
  14.  
  15. public function testLogin(): void
  16. {
  17. $client = http://www.php.net/static::createClient();
  18. $crawler = $client->request('GET', '/login');
  19.  
  20. // Uzupelnij formularz danymi i zaloguj
  21. $dataLogin = [
  22. 'email' => self::TEST_USER_LOGIN,
  23. 'password' => self::TEST_USER_PASSWORD,
  24. //'submit' => 'Login',
  25. ];
  26.  
  27. //$formLogin = $crawler->filter('form')->form();
  28. $formLogin = $crawler->selectButton('Login')->form();
  29.  
  30. //$formLogin['email']->setValue(self::TEST_USER_LOGIN);
  31. //$formLogin['password']->setValue(self::TEST_USER_PASSWORD);
  32. //$formLogin['submit']->setValue('Login');
  33. // OFF $formLogin['_csrf_token"'] = 'It is generated automatically!';
  34.  
  35. //$client->submit($formLogin, $dataLogin);
  36.  
  37. //dd($client->getRequest()->request);
  38.  
  39. // Sprawdz, czy zalogowany -> sprawdza tylko czy email jest w bazie questionmark.gif?
  40. $repositoryUser = http://www.php.net/static::getContainer()->get(UserRepository::class);
  41. $testUser = $repositoryUser->findOneBy(['email' => self::TEST_USER_LOGIN]);
  42. $client->loginUser($testUser);
  43.  
  44. //dd($testUser);
  45.  
  46. $this->assertResponseIsSuccessful();
  47. }
  48. }


Mam prośbę o pomoc w wykonaniu testowania.


Napisany przez: VonSNAKE 20.09.2023, 22:57:24

A pokaż Twig i Kontroler dla routa /login?

Napisany przez: jacek.e3 21.09.2023, 11:28:23

Która wersja Symfony? Masz w kodzie

  1. $client->loginUser($testUser);
więc zakładam, że 5.1+

ten fragment:
  1. $repositoryUser = http://www.php.net/static::getContainer()->get(UserRepository::class);
  2. $testUser = $repositoryUser->findOneBy(['email' => self::TEST_USER_LOGIN]);
  3. $client->loginUser($testUser);

to takie ułatwienie, żeby od razu mieć zalogowanego usera do dalszych testów. Ten kod nawet nie dotyka formularza tylko ustawia usera ze zmiennej $testUser jako zalogowanego użytkownika.

co do reszty to spróbuj tak:
  1. $client = http://www.php.net/static::createClient();
  2. $crawler = $client->request('GET', '/login');
  3.  
  4. // Uzupelnij formularz danymi i zaloguj
  5. $dataLogin = [
  6. 'email' => self::TEST_USER_LOGIN,
  7. 'password' => self::TEST_USER_PASSWORD,
  8. //'submit' => 'Login',
  9. ];
  10.  
  11. //$formLogin = $crawler->filter('form')->form();
  12. $formLogin = $crawler->selectButton('Login')->form();
  13.  
  14. $formLogin['email'] = self::TEST_USER_LOGIN;
  15. $formLogin['password'] = self::TEST_USER_PASSWORD;
  16. $this->client->submit($formLogin);


teraz możesz sprawdzic jakies inne rzeczy np. czy nastąpiło przekierowanie na stronę główną (o ile takie ustawiłeś):
  1. // BTW. dodaj sobie router i generuj sciezki zamiast wstawiac je na sztywno
  2. $router = http://www.php.net/static::getContainer()->get(UrlGeneratorInterface::class);
  3. $this->assertResponseRedirects($router->generate('app_home'));


albo czy zwrócona strona zawiera jakiś tekst np. "zalogowano", możesz też sprawdzić to po zasymulowaniu kliknięcia np:

  1. $client->request('GET', '/home');
  2. $this->assertResponseIsSuccessful();
  3. $this->assertSelectorTextContains('h1', 'Witaj');



Napisany przez: Malinaa 25.09.2023, 14:28:11

Cytat(VonSNAKE @ 20.09.2023, 23:57:24 ) *
A pokaż Twig i Kontroler dla routa /login?


Kontroler

<!--Geshi:502619:php--><pre class="php-brief" style="font-family:monospace;"><div class="head">
  1. [topic=0]oken"</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">"_csrf_token"</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">"97e..."</span> <span class="sy0">/</span>><<span class="sy0">/</span>http://</span>http<span%20class="sy0">:</span><span%20class="co1">//december.com/html/4/element/div.html></span></div><li class="li2"><div class="de2"><span class="sc2"><<span class="sy0">/</span>http://december.com/html/4/element/form.html></span></div>
  2. [/list]<div class="foot">[HTML] [url="./Pobierz-Plik-502620.html"]plaintext[/url] </div></pre><!--/Geshi:502620:html-->
  3.  
  4.  
  5.  
  6. <!--quoteo(post=1261873:http://www.php.net/date=21.09.2023, 12:28:23 :name=jacek.e3)--><div class='quotetop'>Cytat(jacek.e3 @ 21.09.2023, 12:28:23 ) [snapback]1261873[/snapback]</div><div class='quotemain'><!--quotec-->Która wersja Symfony?<!--QuoteEnd--></div><!--QuoteEEnd-->
  7.  
  8.  
  9. Symfony w wersji 5.4
  10.  
  11. Przesłany kod już wcześniej sprawdzałem, ale wg. tego co napisałeś teraz jest tak:
  12.  
  13. [php]class SecurityControllerTest extends AbstractIntegrationWebTestCase
  14. {
  15. public const TEST_USER_LOGIN = 'test@email.com';
  16. public const TEST_USER_PASSWORD = 'Test123';
  17.  
  18. public function testLogin(): void
  19. {
  20. $client = http://www.php.net/static::createClient();
  21. $crawler = $client->request('GET', '/login');
  22.  
  23. $formLogin = $crawler->selectButton('Login')->form();
  24.  
  25. $formLogin['email'] = self::TEST_USER_LOGIN;
  26. $formLogin['password'] = self::TEST_USER_PASSWORD;
  27. $client->submit($formLogin);
  28.  
  29. $router = http://www.php.net/static::getContainer()->get(UrlGeneratorInterface::class);
  30. $this->assertResponseRedirects($router->generate('app_main'));
  31.  
  32. //dd($client->getResponse()->getContent());
  33. }
  34. }


i sypie błędem:

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.


dd($client->getResponse()->getContent());
daje jakiś wynik przekierowania chyba z vendora

<body>
Redirecting to <a href="/login">/login</a>.\n
</body>

i za chiny ten $formLogin nie loguje usera z formularza logowania?

Napisany przez: jacek.e3 25.09.2023, 17:56:43

3 sprawy:
1) jak się logujesz "ręcznie" - to działa?

2) kolega prosił o twiga formularza i kod kontrolera. Nie chodziło nam o wygenerowany kod w htmlu tylko o surowe pliki z twiga i klase controllera.
Formularz powinien mieć dynamicznie generowany token csrf:

  1. <http://december.com/html/4/element/input.html type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" >

a w kontrolerze można dodać np:
  1. $error = $authenticationUtils->getLastAuthenticationError();

i podejrzeć co jest nie tak.

3) Phpunit powinien dać Ci coś więcej niż tylko surową liczbę - wklej co mu tam nie pasuje.

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.

Napisany przez: Malinaa 26.09.2023, 08:19:41

Sprawy

1. Tak, wypełniam pole login, hasło, zaznaczam Agree terms i loguje się.

2. Przesłałem wygenerowany kod HTML, ponieważ tu wszystko widać i jest też token csrf

  1. <http://december.com/html/4/element/input.html type="hidden" id="_csrf_token" name="_csrf_token" value="abc..." />


bynajmniej było widać, teraz to chyba forum nie poradziło sobie z formatowaniem i "brzydko" wyświetla w PHP plaintext

dodatkowo przesyłam kod Twig

{%- block form -%}
{{ form_start(form) }}
{{- form_widget(form) -}}
{{ form_end(form) }}
{%- endblock -%}

w kontrolerze jest dodane:
$error = $authenticationUtils->getLastAuthenticationError();
i nie pokazuje, aby coś tu było nie tak,
chyba, że jest tu mowa o dodaniu w kontrolerze testowym?

3. Oprócz F - fail i liczby jest komunikat

Deprecated: App\Shared\Uuid\Uuid implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in /var/www/src/Shared/Uuid/Uuid.php on line 11

Przesyłam ponownie klasę testu po wprowadzeniu zmian, o których pisałeś chociaż była już wcześniej podana

  1. class SecurityControllerTest extends AbstractIntegrationWebTestCase
  2. {
  3. public const TEST_USER_LOGIN = 'test@email.com';
  4. public const TEST_USER_PASSWORD = 'Test123';
  5.  
  6. public function testLogin(): void
  7. {
  8. $client = http://www.php.net/static::createClient();
  9. $crawler = $client->request('GET', '/login');
  10.  
  11. $formLogin = $crawler->selectButton('Login')->form();
  12.  
  13. $formLogin['email'] = self::TEST_USER_LOGIN;
  14. $formLogin['password'] = self::TEST_USER_PASSWORD;
  15. $client->submit($formLogin);
  16.  
  17. $router = http://www.php.net/static::getContainer()->get(UrlGeneratorInterface::class);
  18. $this->assertResponseRedirects($router->generate('app_main'));
  19. }
  20. }


Powyższa klasa sypie błędem FAILURES... Nie działa.

Napisany przez: jacek.e3 26.09.2023, 13:18:46

Cały czas chodzilo o kontroler do logowania, a nie klase do testowania.

Jeżeli nie ma tam nic innego przy tym failure to w takim razie może wszystko jest tam ok. W zależności od wersji phpunit były różne defaultowe zachowania co zrobić z deprecation errorami.

Zobacz tu: https://symfony.com/doc/current/components/phpunit_bridge.html#disabling-the-deprecation-helper

  1. <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled" />

Napisany przez: Malinaa 27.09.2023, 08:52:27

Ten kontroler podałem w [PHP] pobierz, plaintext ale coś się tu poprzestawiało przy wyświetlaniu, stąd zmyłka (wiem, że podałem kod kontrolera, ale faktycznie gdzieś zaginął w akcji).
Jeśli jest error to raczej nie jest wszystko ok. Zobaczę co pod tym linkiem piszą.

Dodałem

  1. <!-- phpunit.xml.dist -->
  2. <listeners>
  3. <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
  4. <arguments>
  5. <array>
  6. <element key="debug-class-loader"><integer>0</integer></element>
  7. </array>
  8. </arguments>
  9. </listener>
  10. </listeners>

ale nadal wyświetla błąd.

There was 1 failure:

App\Tests\Controller\SecurityControllerTest::testLogin
Failed asserting that Symfony\Component\HttpFoundation\RedirectResponse Object &00000000000009450000000000000000 (
...
) is redirected and has header "Location" with value "/".

Napisany przez: jacek.e3 27.09.2023, 09:20:01

ok, ale jak kontrolera nie było tak dalej nie ma.
W końcu jest za to jakiś konkret. Dostajesz info, że adres strony nie zgadza się z adresem przekierowania. Do tego gdzieś tam wcześniej pisałeś, że content robi redirect na /login

Pamiętasz to?

  1. $error = $authenticationUtils->getLastAuthenticationError();


możesz zdumpować ten $error to się dowiesz, co to za problem. Mój obecny typ to - nieprawidłowy user /hasło a wynika to stąd, że developujesz na jednej bazie, ale do testów jest odpalana lustrzana baza z sufixem "_test" i w niej tez powinny byc zapisane dane do logowania dla tego usera.


Napisany przez: Malinaa 27.09.2023, 11:39:08

Testuje, sprawdzam itp., ale coś to testowanie idzie jak krew z nosa

Klasa kontrolera

  1. class SecurityController extends AbstractController
  2. {
  3. #[Route(path: '/login', name: 'app_login')]
  4. public function login(AuthenticationUtils $authenticationUtils): Response
  5. {
  6. if ($this->getUser()) {
  7. return $this->redirectToRoute('app_main');
  8. }
  9.  
  10. $error = $authenticationUtils->getLastAuthenticationError();
  11. if (http://www.php.net/isset($error)) {
  12. $this->addFlash('danger', $error->getMessage());
  13. }
  14.  
  15. $form = $this->createForm(LoginType::class, [
  16. 'email' => $authenticationUtils->getLastUsername(),
  17. ]);
  18.  
  19. return $this->render('security/login.html.twig', [
  20. 'form' => $form->createView(),
  21. 'error' => $error,
  22. ]);
  23. }
  24.  
  25. // and more...
  26. }


może z redirect mam coś zamieszane?

dump($error) daje null

w kontrolerze mamy
if ($this->getUser()) {} i powinno przekierować,
ale wygląda, że nie wchodzi do tego ifa, czyli nie loguje usera

Pytanie co z bazą, bo czytam, że powinna być osobna "test",
ale nie widzę tu żadnego połączenia i bazy "test", testuje na jednej bazie

Napisany przez: jacek.e3 27.09.2023, 11:49:47

Masz route "app_main"?
Masz usera w bazie testowej?

Spróbuj dodać to dump($error) w kontrolerze i odpal test jeszcze raz;


Napisany przez: Malinaa 27.09.2023, 12:09:31

Mam route 'app_main'
$router = static::getContainer()->get(UrlGeneratorInterface::class);
$this->assertResponseRedirects($router->generate('app_main'));

User jest bazie projektu, a że jest jedna baza to też jest w testowej! Chyba?

Dodaje dump($error) w kontrolerze SecurityController i odpalam test jeszcze raz,
otrzymuję null z dumpa i błąd... wcześniej wymieniony

Kontroler test

  1. class SecurityControllerTest extends AbstractIntegrationWebTestCase
  2. {
  3. public const TEST_USER_LOGIN = 'test@email.com';
  4. public const TEST_USER_PASSWORD = 'Test123';
  5.  
  6. public function testLogin(): void
  7. {
  8. $client = http://www.php.net/static::createClient();
  9. $crawler = $client->request('GET', '/login');
  10.  
  11. $formLogin = $crawler->selectButton('Login')->form();
  12.  
  13. $formLogin['email'] = self::TEST_USER_LOGIN;
  14. $formLogin['password'] = self::TEST_USER_PASSWORD;
  15. $client->submit($formLogin);
  16.  
  17. $router = http://www.php.net/static::getContainer()->get(UrlGeneratorInterface::class);
  18. $this->assertResponseRedirects($router->generate('app_main'));
  19. }
  20. }

Czy
$formLogin['email'] = self::TEST_USER_LOGIN;
$formLogin['password'] = self::TEST_USER_PASSWORD;
wystarcza, aby się zalogować, czy cos tu brakuje?
Sprawdzałem z np. dodatkowo
$formLogin['agreeTerms'] = true;
ale też daje ten sam błąd.
A token, a zakodowane hasło itp.?

Albo $formLogin = $crawler->selectButton('Login')->form() podpowiada, że powinno tu być value.
Czy dla takiego buttona: <button type="submit" id="submit" name="submit" class="btn btn-primary">Login</button> value to na pewno: Login?

Napisany przez: jacek.e3 27.09.2023, 17:22:29

Masz jakis serwer z bazodanowy - mysql ?

Zaloguj się tam i wyświetl bazy danych. Sprawdź, czy jest tam baza danych z suffixem '_test'. Jak jest to wejdz do niej, sprawdz czy masz wszystkie tabele, a w szczegolnosci czy masz tabele z usarami i czy jest w niej rekord dotyczacy Twojego testowego konta.
Sprawdź to, nie zakładaj że to jest to samo.


defaultowy suffix do bazy w srodowisku testowy:
app/config/packages/doctrine.yaml

  1. when@test:
  2. doctrine:
  3. dbal:
  4. # "TEST_TOKEN" is typically set by ParaTest
  5. dbname_suffix: '_test%env(default::TEST_TOKEN)%'



Napisany przez: Malinaa 4.10.2023, 11:26:13

Ustawienia są tak zmienione, że powinno działać na bazie głównej (nie _test) i wygląda, że działa, ponieważ dla repozytorium podbiera dane z bazy bez problemu.

Przykład:

  1. $userRepository = http://www.php.net/static::$container->get(UserRepository::class);
  2. $testUser = $userRepository->findOneBy(['email' => 'test@email.com']);

i otrzymuję dane usera z bazy.

Znaczy się teoretycznie zakładam, a praktycznie sprawdziłem, że powinno działać tak samo,
chociaż pewności nie mam jak to jest z tą bazą _test, na serwerze takiej nie mam, w ustawieniach jest zmienione, aby łączyło z bazą aplikacji.
Po dodaniu dbname_suffix: '_test%env(default::TEST_TOKEN)%' aplikacja się wysypie, nie ma bazy _test.

Patrzę jeszcze na. env, czy tutaj ma być APP_ENV=dev czy przy testach powinno być zmienione na APP_ENV=test?

Napisany przez: jacek.e3 5.10.2023, 07:11:04

Kod

  1. $userRepository = http://www.php.net/static::$container->get(UserRepository::class);
  2. $testUser = $userRepository->findOneBy(['email' => 'test@email.com']);


sprawdzi tylko czy user o takim adresie jest w bazie. Nie sprawdzi czy hasło jest poprawne.

W głównym folderze powinien byc plik konfiguracyjny do phpunit: phpunit.xml.dist
w środku znajdziesz:
  1. <server name="APP_ENV" value="test" force="true" />


Skoro zmieniasz jakieś rzeczy z defaultowym configu i o nich nie piszesz, to nie oczekuj, że ktoś się domyśli co tam zmieniłes. Wrzuc całość na jakiegos githuba to wtedy bedzie sens to kontynuowac.

Napisany przez: Malinaa 5.10.2023, 07:23:26

W phpunit.xml.dis mam

  1. <server name="APP_ENV" value="test" force="true" />


Przy testach może hasło koduje inaczej, pozostaje pytanie jak je sprawdzić?

Nie za bardzo mogę udostępnić ten kod, ale dziękuje za informacje.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)