Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [PHP]Testy w Laravel / php
trifek
post 5.04.2020, 15:26:33
Post #1





Grupa: Zarejestrowani
Postów: 299
Pomógł: 0
Dołączył: 28.09.2015

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


Witam serdecznie,
Uczę się pisania testów w Laravelu. Jako że nie wiem jak powinny wyglądać "profesjonalnie" - to chciałem dopytać czy to, co robię ma sens smile.gif

1. Test 1 - test sprawdzający czy strona działa poprawnie
  1. class HomeTest extends TestCase
  2. {
  3. public function testHomePageWorkCorrectly()
  4. {
  5. //$this->withoutExceptionHandling();
  6. $response = $this->get('/');
  7.  
  8. $response->assertStatus(200);
  9. }
  10. }



2. Test 2 - test logowania z dobrym i błędnym hasłem
  1. class LoginTest extends TestCase
  2. {
  3. public function testUserCanLoginWithCorrectPassword()
  4. {
  5. //$this->withoutExceptionHandling();
  6. $response = $this->post(route('cms.check_admin_login'), [
  7. 'email' => 'lukpeta@icloud.com',
  8. 'password' => 'passw'
  9. ]);
  10. $response->assertRedirect('/psCMS/');
  11. $this->assertTrue(Auth::check());
  12. }
  13.  
  14. public function testUserCannotLoginWithInCorrectPassword()
  15. {
  16. //$this->withoutExceptionHandling();
  17. $response = $this->post(route('cms.check_admin_login'), [
  18. 'email' => 'lukpeta@icloud.com',
  19. 'password' => 'xxxxx'
  20. ]);
  21. $response->assertRedirect('psCMS/login?error=1');
  22. $this->assertFalse(Auth::check());
  23. }
  24. }



3. Test 3 - test modułu reklam. Dodawanie nowej reklamy, sprawdzanie czy istnieje, pobieranie listy reklam, sprawdzanie czy walidacja pól działa, kasowanie
  1. class AdTest extends TestCase
  2. {
  3. use \Illuminate\Foundation\Testing\WithFaker;
  4.  
  5. public function testCreateAd()
  6. {
  7. $user = User::find(1);
  8. $this->be($user);
  9.  
  10. $ad = factory(Ad::class)->create();
  11. $this->post(route('ads.edit') . '/' . $ad->id, $ad->toArray());
  12. $this->assertDatabaseHas('ads', ['id' => $ad->id]);
  13. }
  14.  
  15. public function testAdExist()
  16. {
  17. $user = User::find(1);
  18. $this->be($user);
  19.  
  20. $ad = factory(Ad::class)->create();
  21. $this->post(route('ads.edit') . '/' . $ad->id, $ad->toArray());
  22. $this->assertDatabaseHas('ads', ['id' => $ad->id]);
  23. }
  24.  
  25.  
  26. public function testGetAdsList()
  27. {
  28. $user = User::find(1);
  29. $this->be($user);
  30.  
  31. $ads = factory(Ad::class)->create();
  32. $response = $this->get(route('ads.index'));
  33. $response->assertSee($ads->title);
  34. }
  35.  
  36. public function testCreateAdMustBeCompleted()
  37. {
  38. $user = User::find(1);
  39. $this->be($user);
  40.  
  41. $response = $this->actingAs($user)->post(route('ads.store'), [
  42. 'title' => null,
  43. 'provincial_id' => null,
  44. 'content' => null,
  45. ]);
  46.  
  47. $response->assertSessionHasErrors(['title', 'provincial_id', 'content']);
  48. }
  49.  
  50. public function testCreateAdFromForm()
  51. {
  52. $user = User::find(1);
  53. $this->be($user);
  54. $faker = Faker\Factory::create('pl_PL');
  55. $title = $faker->sentence($nbWords = 6, $variableNbWords = true);
  56. $response = $this->actingAs($user)->post(route('ads.store'), [
  57. 'title' => $title,
  58. 'content' => $faker->text($maxNbChars = 200),
  59. 'provincial_id' => $faker->numberBetween(1, 8),
  60. ]);
  61.  
  62. $this->assertDatabaseHas('ads', ['title' => $title]);
  63. }
  64.  
  65.  
  66. public function testEditAdFromForm()
  67. {
  68. $this->withExceptionHandling();
  69. $user = User::find(1);
  70. $this->be($user);
  71. $faker = Faker\Factory::create('pl_PL');
  72.  
  73. $ad = factory(Ad::class)->create();
  74. $id = $ad->id;
  75.  
  76. $title = $faker->sentence($nbWords = 6, $variableNbWords = true);
  77. $response = $this->actingAs($user)->post(route('ads.update') . '/' . $id, [
  78. 'title' => $title,
  79. 'content' => $faker->text($maxNbChars = 200),
  80. 'provincial_id' => $faker->numberBetween(1, 8),
  81. 'id' => $id
  82. ]);
  83.  
  84. //dd($response->getContent());
  85.  
  86. $this->assertDatabaseHas('ads', ['title' => $title, 'id' => $id]);
  87. }
  88.  
  89.  
  90. public function testDeleteAd()
  91. {
  92. //$this->withExceptionHandling();
  93. //$this->withoutExceptionHandling();
  94. $user = User::find(1);
  95. $this->be($user);
  96.  
  97. $ad = factory(Ad::class)->create();
  98. $id = $ad->id;
  99.  
  100. $faker = Faker\Factory::create('pl_PL');
  101. $title = $faker->sentence($nbWords = 6, $variableNbWords = true);
  102. $response = $this->actingAs($user)->post(route('ads.destroy'), [
  103. 'title' => $title,
  104. 'content' => $faker->text($maxNbChars = 200),
  105. 'provincial_id' => $faker->numberBetween(1, 8),
  106. //'id'=> $id,
  107. 'id' => [$id]
  108. ]);
  109.  
  110. $this->assertDatabaseMissing('ads', ['id' => $ad->id]);
  111. }
  112.  
  113.  
  114. }



Czy takie testy są poprawne? Czy raczej powinny wyglądać inaczej?smile.gif
Go to the top of the page
+Quote Post
Pyton_000
post 5.04.2020, 18:44:31
Post #2





Grupa: Zarejestrowani
Postów: 7 929
Pomógł: 1389
Dołączył: 26.10.2005

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


Takie testy są ok. Nazywają się testami Integracyjnymi lub akceptacyjnymi ( w zależności kto patrzy smile.gif )
Generalnie tutaj testujesz czy funkcjonalność zadana w ogóle działa czyli zapisujesz i sprawdzasz czy się zrobił.

Do tego możesz dołożyć testy Unit które będą testować wybraną klasę z logiką czyli np. masz klasę która generuje Ci coś a twoim zadaniem jest sprawdzić czy klasa będzie się zachowywała w najróżniejszych przypadkach czyli jak dasz dobre wartości to dobry wynik, jak dasz złe wartości to błąd, jak nie dasz wartości to błąd itd.
Go to the top of the page
+Quote Post
Rysh
post 5.04.2020, 20:04:57
Post #3





Grupa: Zarejestrowani
Postów: 817
Pomógł: 111
Dołączył: 11.09.2006
Skąd: Biała Podlaska

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


Tak jak napisał kolega powyżej, testy są OK - ale można je napisać o wiele lepiej.
  1. $this->assertAuthenticated()

zamiast:
  1. $this->assertTrue(Auth::check());


Tutaj widać, że budowanie URL leży:
  1. $this->post(route('ads.edit') . '/' . $ad->id, $ad->toArray());


Fakera nie musisz tworzyć za każdym razem, masz przecież trait'a którego możeszużyć:
  1. <?php
  2.  
  3. namespace Tests\Feature;
  4.  
  5. use Illuminate\Foundation\Testing\WithFaker;
  6. use Tests\TestCase;
  7.  
  8. /**
  9.  * Class WebControllerTest
  10.  */
  11. class WebControllerTest extends TestCase
  12. {
  13. use WithFaker;
  14.  
  15. public function testFaker(): void
  16. {
  17. $this->faker->email;
  18. }
  19. }


--------------------
Go to the top of the page
+Quote Post
trifek
post 6.04.2020, 19:31:47
Post #4





Grupa: Zarejestrowani
Postów: 299
Pomógł: 0
Dołączył: 28.09.2015

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


Cytat(Rysh @ 5.04.2020, 21:04:57 ) *
Tak jak napisał kolega powyżej, testy są OK - ale można je napisać o wiele lepiej.
  1. $this->assertAuthenticated()

zamiast:
  1. $this->assertTrue(Auth::check());


Tutaj widać, że budowanie URL leży:
  1. $this->post(route('ads.edit') . '/' . $ad->id, $ad->toArray());


Fakera nie musisz tworzyć za każdym razem, masz przecież trait'a którego możeszużyć:
  1. <?php
  2.  
  3. namespace Tests\Feature;
  4.  
  5. use Illuminate\Foundation\Testing\WithFaker;
  6. use Tests\TestCase;
  7.  
  8. /**
  9.  * Class WebControllerTest
  10.  */
  11. class WebControllerTest extends TestCase
  12. {
  13. use WithFaker;
  14.  
  15. public function testFaker(): void
  16. {
  17. $this->faker->email;
  18. }
  19. }


Dziękuję bardzo za uwagi / opinie smile.gif


  1. $this->assertFalse(Auth::check());

A jak taki test zapisać? smile.gif

Cytat(Pyton_000 @ 5.04.2020, 19:44:31 ) *
Takie testy są ok. Nazywają się testami Integracyjnymi lub akceptacyjnymi ( w zależności kto patrzy smile.gif )
Generalnie tutaj testujesz czy funkcjonalność zadana w ogóle działa czyli zapisujesz i sprawdzasz czy się zrobił.

Do tego możesz dołożyć testy Unit które będą testować wybraną klasę z logiką czyli np. masz klasę która generuje Ci coś a twoim zadaniem jest sprawdzić czy klasa będzie się zachowywała w najróżniejszych przypadkach czyli jak dasz dobre wartości to dobry wynik, jak dasz złe wartości to błąd, jak nie dasz wartości to błąd itd.


W firmach, które testy najczęściej się pisze? Pewnie te integracyjne? Unit testy idą do klas "nie laravelowych?" smile.gif
Go to the top of the page
+Quote Post
Rysh
post 7.04.2020, 18:41:10
Post #5





Grupa: Zarejestrowani
Postów: 817
Pomógł: 111
Dołączył: 11.09.2006
Skąd: Biała Podlaska

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


Z tego co zaobserwowałem, to w firmach rzadko kiedy piszę się testy wink.gif

Unit: testy które testują daną klasę - tylko klasę, dajesz input do metody i sprawdzasz czy wynik jest spełnia Twoje oczekiwania, nie interesuje Cie za bardzo reszta.
Feature: to testy które testują żądania do strony i oczekiwany response, czyli wysyłasz formularz, odbierasz błąd walidacji lub zwrócone dane. Następnie sprawdzasz czy zwrócone dane są zgodne z oczekiwaniami, sprawdzasz również status HTTP (w przypadku REST API - bardzo ważne) i inne rzeczy (z czasem sam ogarniesz, co testować a czego nie).

Co jest bardzo przydatne moim zdaniem, to code coverage - puszczasz testy na całość, i pokazuje Ci miejsca których nie masz przetestowanych. Czyli żaden kod podczas wykonywania testów nie wszedł do danej instrukcji - czyli przewidziałeś pewną sytuację, ale nie przetestowałeś jej. Tak to wygląda w IDE:


Linijka 45 nie została przetestowana, 44 i 48 już tak.

Warto sobie po testować całe klasy (unit) wraz z kontrolerami (feature). Niektórych czasem nie ma sensu, ale to od programisty zależy. I oczywiście nie testujesz obcych paczek, tylko swój kod który napisałeś.

Pisanie testów, owocuje w przyszłości, gdy zmienisz drobną rzecz, może się okazać że resposne się zmienił - testami to wychwycisz. Bez wychwycenia zmiany response, front może się posypać - czego nikt by nie chciał.
No i zmiany commitujesz dopiero jak wszystkie testy są wykonane z sukcesem. Tutaj warto sobie dodać również automatyczne wykonywanie testów po przesłaniu zmian na GIT, więc nawet jak zapomnisz puścić testów lokalnie, to gitlab czy inny, poinformuje Cię o tym.

Cytat
A jak taki test zapisać? smile.gif


Ja bym zapisał to tak, ale co programista to inny sposób - ja staram się używać, tego co mi podpowiada IDE.
  1. $this->assertFalse($this->isAuthenticated());


--------------------
Go to the top of the page
+Quote Post
markonix
post 8.04.2020, 17:42:45
Post #6





Grupa: Zarejestrowani
Postów: 2 700
Pomógł: 289
Dołączył: 16.12.2008
Skąd: Śląsk

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


Tutaj parę ściąg, aby rozróżnić integracyjne od jednostkowych:
https://www.google.com/search?q=2+unit+test...off&tbm=vid
smile.gif

Osobiście, ze względu na braki kadrowo/czasowe pisze głównie integracyjne, są one bardziej praktyczne, weryfikują działanie podobnie do testera manualnego, więc po prostu robią to co początkujący programista robi sam po jakimś update - przeklikuje system.


--------------------
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: 30.05.2020 - 16:52