Artikel

Pelajari cara melakukan pengujian di Laravel dengan contoh sederhana, menggunakan PHPUnit dan PEST

Terkait pengujian otomatis atau pengujian unit, dalam bahasa pemrograman apa pun, ada dua pendapat yang berlawanan:

  • Buang-buang waktu
  • Anda tidak dapat melakukannya tanpanya

Jadi, dengan artikel ini kami akan mencoba meyakinkan yang pertama, terutama dengan menunjukkan betapa mudahnya memulai pengujian otomatis di Laravel.

Pertama mari kita bicara tentang "mengapa", dan kemudian mari kita lihat beberapa contoh bagaimana caranya.

Mengapa kita memerlukan pengujian otomatis

Tes otomatis menjalankan bagian kode dan melaporkan kesalahan apa pun. Itulah cara paling sederhana untuk menggambarkannya. Bayangkan meluncurkan fitur baru di sebuah aplikasi, lalu asisten robot pribadi akan menguji fitur baru tersebut secara manual, sekaligus menguji apakah kode baru tersebut tidak merusak fitur lama.

Inilah keuntungan utamanya: menguji ulang semua fitur secara otomatis. Ini mungkin tampak seperti pekerjaan ekstra, tetapi jika Anda tidak menyuruh “robot” untuk melakukannya, sebaiknya kita melakukannya secara manual, bukan? 

Atau fitur baru dapat dirilis tanpa menguji apakah fitur tersebut berfungsi, dengan harapan pengguna akan melaporkan bug.

Tes otomatis dapat memberi kita beberapa keuntungan:

  • Menghemat waktu pengujian manual;
  • Mereka memungkinkan Anda menghemat waktu baik pada fungsi baru yang diimplementasikan maupun pada fungsi konsolidasi dengan menghindari regresi;
  • Lipat gandakan manfaat ini dengan semua fitur baru dan semua fitur yang sudah diterapkan;
  • Tiga poin sebelumnya berlaku untuk setiap versi baru;
  • ...

Coba bayangkan aplikasi Anda dalam satu atau dua tahun, dengan pengembang baru di tim yang tidak mengetahui kode yang ditulis pada tahun-tahun sebelumnya, atau bahkan cara mengujinya. 

Tes otomatis pertama kami

Untuk melakukan yang pertama pengujian otomatis di Laravel, Anda tidak perlu menulis kode apa pun. Ya, Anda membacanya dengan benar. Semuanya sudah dikonfigurasi dan disiapkan pada pra-instalasidefinite dari Laravel, termasuk contoh dasar pertama.

Anda dapat mencoba menginstal proyek Laravel dan segera menjalankan pengujian pertama:

laravel new project
cd project
php artisan test

Ini akan menjadi hasil di konsol Anda:

Jika kita melihat pada bagian sebelumnyadefimalam Laravel /tests, kami memiliki dua file:

tes/Fitur/ExampleTest.php :

class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

Anda tidak perlu mengetahui sintaks apa pun untuk memahami apa yang terjadi di sini: muat halaman beranda dan periksa apakah kode status HTTP è "200 OK".

Juga dikenal sebagai nama metode test_the_application_returns_a_successful_response() menjadi teks yang dapat dibaca ketika Anda melihat hasil tes, cukup dengan mengganti simbol garis bawah dengan spasi.

tes/Unit/ExampleTest.php :

class ExampleTest extends TestCase
{
    public function test_that_true_is_true()
    {
        $this->assertTrue(true);
    }
}

Tampaknya agak tidak ada gunanya, memeriksa apakah ini benar? 

Kami akan berbicara secara khusus tentang pengujian unit nanti. Untuk saat ini, Anda perlu memahami apa yang umumnya terjadi di setiap pengujian.

  • Setiap file tes di folder /tests adalah kelas PHP yang memperluas TestCase Unit PHP
  • Dalam setiap kelas, Anda dapat membuat beberapa metode, biasanya satu metode untuk menguji suatu situasi
  • Dalam setiap metode terdapat tiga tindakan: persiapan situasi, kemudian tindakan, dan kemudian memverifikasi (menegaskan) apakah hasilnya sesuai dengan yang diharapkan.

Secara struktural, hanya itu yang perlu Anda ketahui, sisanya bergantung pada hal-hal yang ingin Anda uji.

Untuk menghasilkan kelas pengujian kosong, cukup jalankan perintah ini:

php artisan make:test HomepageTest

File dibuat tests/Feature/HomepageTest.php:

class HomepageTest extends TestCase
{
    // Replace this method with your own ones
    public function test_example()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

Sekarang mari kita lihat apa yang terjadi jika kode pengujian gagal di Laravel

Sekarang mari kita lihat apa yang terjadi jika pernyataan pengujian tidak memberikan hasil yang diharapkan.

Mari kita ubah contoh tes menjadi ini:

class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/non-existing-url');
 
        $response->assertStatus(200);
    }
}
 
 
class ExampleTest extends TestCase
{
    public function test_that_true_is_false()
    {
        $this->assertTrue(false);
    }
}

Dan sekarang, jika kita menjalankan perintah php artisan test lagi:

 FAIL  Tests\Unit\ExampleTest
⨯ that true is true
 
 FAIL  Tests\Feature\ExampleTest
⨯ the application returns a successful response
 
---
 
• Tests\Unit\ExampleTest > that true is true
Failed asserting that false is true.
 
at tests/Unit/ExampleTest.php:16
   12▕      * @return void
   13▕      */
   14▕     public function test_that_true_is_true()
   15▕     {
➜  16▕         $this->assertTrue(false);
   17▕     }
   18▕ }
   19▕
 
• Tests\Feature\ExampleTest > the application returns a successful response
Expected response status code [200] but received 404.
Failed asserting that 200 is identical to 404.
 
at tests/Feature/ExampleTest.php:19
   15▕     public function test_the_application_returns_a_successful_response()
   16▕     {
   17▕         $response = $this->get('/non-existing-url');
   18▕
➜  19▕         $response->assertStatus(200);
   20▕     }
   21▕ }
   22▕
 
 
Tests:  2 failed
Time:   0.11s

Ada dua tes yang gagal, ditandai sebagai GAGAL, ​​dengan penjelasan di bawah dan panah yang menunjuk ke baris tes yang gagal. Kesalahan ditunjukkan dengan cara ini.

Contoh: Menguji kode formulir pendaftaran di Laravel

Misalkan kita mempunyai sebuah formulir dan kita perlu menguji berbagai kasus: kita memeriksa apakah formulir tersebut gagal dengan data yang tidak valid, kita memeriksa apakah formulir tersebut berhasil dengan input yang benar, dll.

Paket starter resmi oleh Laravel Breeze termasuk saya menguji fungsionalitas di dalamnya. Mari kita lihat beberapa contoh dari sana:

tests/Feature/RegistrationTest.php

use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
 
class RegistrationTest extends TestCase
{
    use RefreshDatabase;
 
    public function test_registration_screen_can_be_rendered()
    {
        $response = $this->get('/register');
 
        $response->assertStatus(200);
    }
 
    public function test_new_users_can_register()
    {
        $response = $this->post('/register', [
            'name' => 'Test User',
            'email' => 'test@example.com',
            'password' => 'password',
            'password_confirmation' => 'password',
        ]);
 
        $this->assertAuthenticated();
        $response->assertRedirect(RouteServiceProvider::HOME);
    }
}

Di sini kita mempunyai dua pengujian dalam satu kelas, karena keduanya terkait dengan formulir pendaftaran: satu memeriksa apakah formulir dimuat dengan benar dan yang lain memeriksa apakah pengiriman berfungsi dengan baik.

Mari kita kenali dua metode lagi untuk memverifikasi hasil, dua pernyataan lagi: $this->assertAuthenticated()$response->assertRedirect(). Anda dapat memeriksa semua pernyataan yang tersedia di dokumentasi resmi Unit PHP e Respon Laravel . Perhatikan bahwa beberapa pernyataan umum muncul mengenai subjek ini $this, sementara yang lain memeriksa secara spesifik $responsedari panggilan rute.

Hal penting lainnya adalah use RefreshDatabase;pernyataan, dengan coretan, disisipkan di atas kelas. Hal ini diperlukan ketika tindakan pengujian dapat mempengaruhi database, seperti dalam contoh ini, logging menambahkan entri baru ke dalam database userstabel basis data. Untuk ini, Anda harus membuat database pengujian terpisah yang akan diperbarui php artisan migrate:freshsetiap kali tes dijalankan.

Anda memiliki dua opsi: membuat database terpisah secara fisik atau menggunakan database SQLite dalam memori. Keduanya dikonfigurasi dalam file phpunit.xmldisediakan secara defaultdefinita dengan LARAVEL. Secara khusus, Anda memerlukan bagian ini:

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="BCRYPT_ROUNDS" value="4"/>
    <env name="CACHE_DRIVER" value="array"/>
    <!-- <env name="DB_CONNECTION" value="sqlite"/> -->
    <!-- <env name="DB_DATABASE" value=":memory:"/> -->
    <env name="MAIL_MAILER" value="array"/>
    <env name="QUEUE_CONNECTION" value="sync"/>
    <env name="SESSION_DRIVER" value="array"/>
    <env name="TELESCOPE_ENABLED" value="false"/>
</php>

Lihat DB_CONNECTIONDB_DATABASEmana yang dikomentari? Jika Anda memiliki SQLite di server Anda, tindakan paling sederhana adalah dengan menghapus komentar pada baris tersebut dan pengujian Anda akan dijalankan terhadap database dalam memori tersebut.

Dalam pengujian ini kami mengatakan bahwa pengguna berhasil diautentikasi dan diarahkan ke beranda yang benar, namun kami juga dapat menguji data aktual di database.

Selain kode ini:

$this->assertAuthenticated();
$response->assertRedirect(RouteServiceProvider::HOME);

Kita juga bisa menggunakan pernyataan pengujian database dan lakukan sesuatu seperti ini:

$this->assertDatabaseCount('users', 1);
 
// Or...
$this->assertDatabaseHas('users', [
    'email' => 'test@example.com',
]);

Contoh halaman Login

Sekarang mari kita lihat contoh lain halaman Login dengan Laravel Breeze

tests/Feature/AuthenticationTest.php:

class AuthenticationTest extends TestCase
{
    use RefreshDatabase;
 
    public function test_login_screen_can_be_rendered()
    {
        $response = $this->get('/login');
 
        $response->assertStatus(200);
    }
 
    public function test_users_can_authenticate_using_the_login_screen()
    {
        $user = User::factory()->create();
 
        $response = $this->post('/login', [
            'email' => $user->email,
            'password' => 'password',
        ]);
 
        $this->assertAuthenticated();
        $response->assertRedirect(RouteServiceProvider::HOME);
    }
 
    public function test_users_can_not_authenticate_with_invalid_password()
    {
        $user = User::factory()->create();
 
        $this->post('/login', [
            'email' => $user->email,
            'password' => 'wrong-password',
        ]);
 
        $this->assertGuest();
    }
}

Ini tentang formulir login. Logikanya mirip dengan registrasi kan? Namun tiga metode, bukan dua, jadi ini adalah contoh pengujian skenario baik dan buruk. Jadi, logika umumnya adalah Anda harus menguji kedua kasus tersebut: kapan semuanya berjalan baik dan kapan gagal.

Buletin inovasi
Jangan lewatkan berita terpenting tentang inovasi. Daftar untuk menerimanya melalui email.

Juga, apa yang Anda lihat dalam tes ini adalah penggunaan Pabrik Basis Data : Laravel membuat pengguna palsu ( sekali lagi, pada database pengujian Anda yang diperbarui ) dan kemudian mencoba masuk, dengan kredensial yang benar atau salah.

Sekali lagi, Laravel menghasilkan pra pabrikdefinita dengan data palsu untuk itu Usermodel, di luar kotak.

database/factories/UserFactory.php:

class UserFactory extends Factory
{
    public function definition()
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}

Soalnya, berapa banyak hal yang disiapkan oleh Laravel sendiri, lalu mudahkah kita memulai pengujiannya?

Jadi jika kita mengeksekusi php artisan testsetelah menginstal Laravel Breeze, kita akan melihat sesuatu seperti ini:

 PASS  Tests\Unit\ExampleTest
✓ that true is true
 
 PASS  Tests\Feature\Auth\AuthenticationTest
✓ login screen can be rendered
✓ users can authenticate using the login screen
✓ users can not authenticate with invalid password
 
 PASS  Tests\Feature\Auth\EmailVerificationTest
✓ email verification screen can be rendered
✓ email can be verified
✓ email is not verified with invalid hash
 
 PASS  Tests\Feature\Auth\PasswordConfirmationTest
✓ confirm password screen can be rendered
✓ password can be confirmed
✓ password is not confirmed with invalid password
 
 PASS  Tests\Feature\Auth\PasswordResetTest
✓ reset password link screen can be rendered
✓ reset password link can be requested
✓ reset password screen can be rendered
✓ password can be reset with valid token
 
 PASS  Tests\Feature\Auth\RegistrationTest
✓ registration screen can be rendered
✓ new users can register
 
 PASS  Tests\Feature\ExampleTest
✓ the application returns a successful response
 
Tests:  17 passed
Time:   0.61s

Tes fungsional dibandingkan dengan tes unit dan lainnya

Anda telah melihat subfoldernya tests/Feature e tests/Unit ?. 

Apa perbedaan di antara keduanya? 

Secara global, di luar ekosistem Laravel/PHP, terdapat beberapa jenis pengujian otomatis. Anda dapat menemukan istilah seperti:

  • Tes satuan
  • Pengujian fitur
  • Tes integrasi
  • Tes fungsional
  • Pengujian ujung ke ujung
  • Tes penerimaan
  • Tes asap
  • dll.

Kedengarannya rumit, dan perbedaan sebenarnya antara jenis tes ini terkadang tidak jelas. Itu sebabnya Laravel menyederhanakan semua istilah yang membingungkan ini dan mengelompokkannya menjadi dua: unit/fitur.

Sederhananya, pengujian fitur mencoba menjalankan fungsionalitas sebenarnya dari aplikasi Anda: mendapatkan URL, memanggil API, meniru perilaku persis seperti mengisi formulir. Pengujian fitur biasanya melakukan operasi yang sama atau serupa seperti yang dilakukan pengguna proyek mana pun, secara manual, di kehidupan nyata.

Tes unit memiliki dua arti. Secara umum, Anda mungkin menemukan bahwa pengujian otomatis apa pun disebut “pengujian unit” dan keseluruhan prosesnya dapat disebut “pengujian unit”. Namun dalam konteks fungsionalitas versus unit, proses ini adalah tentang pengujian unit kode non-publik tertentu, secara terpisah. Misalnya, Anda memiliki kelas Laravel dengan metode yang menghitung sesuatu, seperti total harga pesanan dengan parameter. Oleh karena itu, pengujian unit akan menyatakan apakah hasil yang benar dikembalikan dari metode tersebut (unit kode), dengan parameter yang berbeda.

Untuk menghasilkan pengujian unit, Anda perlu menambahkan tanda:

php artisan make:test OrderPriceTest --unit

Kode yang dihasilkan sama dengan tes pra unitdefiSistem Laravel:

class OrderPriceTest extends TestCase
{
    public function test_example()
    {
        $this->assertTrue(true);
    }
}

Seperti yang Anda lihat, itu tidak ada RefreshDatabase, dan ini adalah salah satunya defidefinisi pengujian unit yang paling umum: tidak menyentuh database, berfungsi sebagai "kotak hitam", diisolasi dari aplikasi yang sedang berjalan.

Coba tiru contoh yang saya sebutkan tadi, bayangkan kita mempunyai kelas jasa OrderPrice.

app/Services/OrderPriceService.php:

class OrderPriceService
{
    public function calculatePrice($productId, $quantity, $tax = 0.0)
    {
        // Some kind of calculation logic
    }
}

Kemudian, pengujian unit akan terlihat seperti ini:

class OrderPriceTest extends TestCase
{
    public function test_single_product_no_taxes()
    {
        $product = Product::factory()->create(); // generate a fake product
        $price = (new OrderPriceService())->calculatePrice($product->id, 1);
        $this->assertEquals(1, $price);
    }
 
    public function test_single_product_with_taxes()
    {
        $price = (new OrderPriceService())->calculatePrice($product->id, 1, 20);
        $this->assertEquals(1.2, $price);
    }
 
    // More cases with more parameters
}

Dalam pengalaman pribadi saya dengan proyek Laravel, sebagian besar pengujian adalah pengujian Fitur, bukan pengujian Unit. Pertama, Anda perlu menguji apakah aplikasi Anda berfungsi, seperti cara orang menggunakannya.

Selanjutnya, jika Anda memiliki perhitungan atau logika khusus, Anda bisa definire sebagai sebuah unit, dengan parameter, Anda dapat membuat pengujian unit khusus untuk itu.

Terkadang, menulis tes memerlukan modifikasi kode itu sendiri dan memfaktorkannya ulang agar lebih “dapat diuji”: memisahkan unit ke dalam kelas atau metode khusus.

Kapan/bagaimana melakukan tes?

Apa sebenarnya kegunaan ini php artisan test, kapan sebaiknya Anda menjalankannya?

Ada beberapa pendekatan yang berbeda, bergantung pada alur kerja bisnis Anda, namun umumnya Anda perlu memastikan bahwa semua pengujian bersifat “hijau” (yaitu bebas kesalahan) sebelum memasukkan perubahan kode akhir ke repositori.

Kemudian, Anda mengerjakan tugas Anda secara lokal, dan ketika Anda merasa sudah selesai, jalankan beberapa tes untuk memastikan Anda tidak merusak apa pun. Ingat, kode Anda mungkin menyebabkan bug tidak hanya pada logika Anda tetapi juga secara tidak sengaja merusak beberapa perilaku lain dalam kode orang lain yang ditulis sejak lama.

Jika kita melangkah lebih jauh, otomatisasi dapat dilakukan banyak hal-hal. Dengan berbagai alat CI/CD, Anda dapat menentukan pengujian yang akan dijalankan setiap kali seseorang melakukan perubahan ke cabang Git tertentu atau sebelum menggabungkan kode ke cabang produksi. Alur kerja paling sederhana adalah menggunakan Github Actions, yang saya punya video terpisah yang membuktikannya.

Apa yang harus Anda uji?

Ada perbedaan pendapat mengenai seberapa besar apa yang disebut “cakupan pengujian” seharusnya: coba setiap kemungkinan operasi dan kasus di setiap halaman, atau batasi pekerjaan pada bagian yang paling penting.

Faktanya, saya setuju dengan orang-orang yang menuduh pengujian otomatis memakan waktu lebih lama daripada memberikan manfaat sebenarnya. Ini bisa terjadi jika Anda menulis tes untuk setiap detail. Meskipun demikian, ini mungkin diperlukan oleh proyek Anda: pertanyaan utamanya adalah “berapa harga dari potensi kesalahan”.

Dengan kata lain, Anda perlu memprioritaskan upaya pengujian Anda dengan mengajukan pertanyaan “Apa yang akan terjadi jika kode ini gagal?” Jika sistem pembayaran Anda mengalami bug, maka akan berdampak langsung pada bisnis. Jadi jika fungsi peran/izin Anda rusak, ini adalah masalah keamanan yang sangat besar.

Saya suka bagaimana Matt Stauffer mengatakannya di sebuah konferensi: “Anda harus terlebih dahulu menguji hal-hal yang, jika gagal, akan membuat Anda dipecat dari pekerjaan Anda.” Tentu saja itu berlebihan, tetapi Anda mengerti maksudnya: cobalah hal-hal penting terlebih dahulu. Dan fitur lainnya, jika Anda punya waktu.

PEST: alternatif baru untuk PHPUnit

Semua contoh di atas didasarkan pada alat pra-pengujian Laraveldefimalam: Unit PHP . Namun selama bertahun-tahun, alat lain telah muncul di ekosistem dan salah satu alat terbaru yang populer adalah HAMA . Dibuat oleh karyawan resmi Laravel Nuno Maduro , bertujuan untuk menyederhanakan sintaksis, membuat penulisan kode untuk pengujian menjadi lebih cepat.

Di bawah tenda, ia berjalan su PHPUnit, sebagai lapisan tambahan, hanya mencoba meminimalkan beberapa bagian yang berulangdefiakhir dari kode PHPUnit.

Mari kita lihat sebuah contoh. Ingat kelas tes pra fiturdefinited di Laravel? Aku akan mengingatkanmu:

namespace Tests\Feature;
 
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

Tahukah Anda seperti apa tes yang sama dengan PEST?

test('the application returns a successful response')->get('/')->assertStatus(200);

Ya, SATU baris kode dan hanya itu. Jadi, tujuan PEST adalah menghilangkan overhead dari:

  • Membuat kelas dan metode untuk semuanya;
  • Perpanjangan kasus uji;
  • Dengan menempatkan tindakan pada baris terpisah: di PEST Anda dapat menyatukannya.

Untuk menghasilkan pengujian PEST di Laravel, Anda perlu menentukan flag tambahan:

php artisan make:test HomepageTest --pest

Saat tulisan ini dibuat, PEST cukup populer di kalangan pengembang Laravel, namun terserah pada preferensi pribadi Anda apakah akan menggunakan alat tambahan ini dan mempelajari sintaksnya, serta catatan PHPUnit.

BlogInnovazione.it

Buletin inovasi
Jangan lewatkan berita terpenting tentang inovasi. Daftar untuk menerimanya melalui email.

Artikel Terbaru

Intervensi inovatif dalam Augmented Reality, dengan penampil Apple di Poliklinik Catania

Operasi oftalmoplasti menggunakan penampil komersial Apple Vision Pro dilakukan di Poliklinik Catania…

3 Mei 2024

Manfaat Halaman Mewarnai untuk Anak - dunia keajaiban untuk segala usia

Mengembangkan keterampilan motorik halus melalui mewarnai mempersiapkan anak untuk keterampilan yang lebih kompleks seperti menulis. Mewarnai…

2 Mei 2024

Masa Depan Ada di Sini: Bagaimana Industri Perkapalan Merevolusi Perekonomian Global

Sektor angkatan laut adalah kekuatan ekonomi global sejati, yang telah menuju pasar 150 miliar...

1 Mei 2024

Penerbit dan OpenAI menandatangani perjanjian untuk mengatur aliran informasi yang diproses oleh Kecerdasan Buatan

Senin lalu, Financial Times mengumumkan kesepakatan dengan OpenAI. FT melisensikan jurnalisme kelas dunianya…

April 30 2024