Cara menggunakan php assertion error

Halo fellas! Baru aja artikel https://medium.com/@kiddy.xyz/mengenal-test-driven-development-d8e838236aca dirilis tapi semangat saya masih menggebu untuk berbagi insight! Oke kita lanjut ya.

Kita akan belajar tentang PHP Unit Test, yaitu salah satu metode testing TDD di PHP. Pada PHP Unit Test ini kita tidak menggunakan PHP Native ya, tapi langsung menggunakan Laravel dan metode Unit Testnya adalah HTTP Test atau menguji coba HTTP (URL kita) yang telah kita sambungkan ke route.

Sebelum mulai saya mau kasitau dulu, karena kita akan menggunakan projek saya maka saya akan kasitau bahwa projek saya menggunakan Laravel 5.7 dan wajib menggunakan PHP ≥ 7.0.

Saya ngga sarankan agan untuk menggunakan PHP ≤ 7.0 karena saya ngga tau Unit Test ataupun Laravelnya bakalan beda atau ngga dengan versi yang saya gunakan. So cekidot.

Pertama silahkan clone repository saya dulu disini. https://github.com/kiddyxyz/laravel-crud-inventory, setelah itu silahkan kalian konfigurasi sendiri seperti databasenya, lalu composer install seperti biasa.

Setelah itu jangan lupa jalankan migratenya, didalamnya sudah ada kok. Jangan lupa juga jalankan seedernya, biar ada data awalnya. Kalo ngga mau nge-seed juga ngga apa kok, opsional aja hehehe.

Kalian ngga perlu nyetting lokasi URL-nya di server local atau jalanin dengan artisan serve karena kita akan jalanin PHPUnit aja kok.

Homepage

Product Page

Buat yang kepo ini tuh projek apa, ini sebenernya tugas perkuliahan saya pake Laravel. Karena saya malas untuk membuat projek baru dan projek ini sudah cukup baik untuk dasar strukturnya jadi pake ini saja ya hahaha.

Oke lanjut, sekarang kita cek strukturnya.

Kita akan fokus ke dua folder pada saat ini, folder tests dan folder Controllers.

Folder tests

Folder Controllers

Tak jelasin dulu deh, jadi untuk pertama kita akan menyamakan isi struktur folder tests dengan folder code yang akan kita ujicoba.

Kita akan membuat struktur folder tests mirip yaitu kita akan membuat folder Http dan didalamnya ada folder Controllers. Kenapa begitu? Biar enak aja strukturnya, jadi jelas class mana yang diuji coba.

Selain itu nama nya akan menjadi NamaFileTest, sebagai contoh ProductControllerTest, fungsinya untuk menjelaskan bahwa isi test didalam ini adalah semua unit test dari class tersebut.

Oke tanpa basa basih kita akan mencoba dengan ProductControllerTest. Silahkan jalankan code dibawah ini.

php artisan make:test Http/Controllers/ProductControllerTest

Lalu liat strukturnya dibawah ini:

Struktur folder tests

Saat ini kita sudah mendapatkan satu unit test pertama kita, yuk langsung buka classnya.

Setelah dibuka maka codenya akan seperti dibawah ini:


namespace Tests\Feature\Http\Controllers;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ProductControllerTest extends TestCase
{
/**
* A basic feature test example.
*
*
@return void
*/
public function testExample()
{
$response = $this->get('/');

$response->assertStatus(200);
}
}

Sebelum kita ubah perlu saya jelaskan dulu ada dua teknik dalam membuat unit test, ada dengan cara menambahkan kata “test” didalam function, ada juga yang membuatnya menjadi docs comment, kedua hal ini valid dan dianggap sebagai unit test, sisanya terserah kalian saja.

public function test_store_data()
{
//TODO: code inside here --Created by Kiddy
}

/**
*
@test
*/
public function it_stores_data()
{
//TODO: code inside here --Created by Kiddy
}

Kedua hal ini dianggap sebagai unit test, kalau kalian menggunakan PHPStorm maka akan muncul tanda hijau disebelah kiri yang menandakan ini adalah unit test.

Contoh unit test.

Nah biasanya programmer yang ngga suka dengan kata test didalam method menggantinya dengan kata “it” atau kata lainnya biar lebih baik grammarnya. Sisanya tinggal kesepakatan tim saja atau yang kamu suka aja hehehe, kalau kerjanya sama tim sih sepakatin ya!

Untuk tutorial kali ini kita akan menggunakan kata “it”, ok?

Sebelum memulai unit test jangan lupa siapkan factory, factory adalah semacam Seeder yang akan dipanggil saat dibutuhkan di Unit Test, karena projek saya memerlukan autentikasi dengan login.

Cara membuatnya adalah:

php artisan make:factory namaFactory

Nah pertama kita akan membuat Factory untuk kategori produk

php artisan make:factory CategoryFactory

Kita tidak akan membuat UserFactory karena sudah ada, cek aja.

Nanti akan muncul pada folder database/factory. Setelah itu ubah CategoryFactory milikmu menjadi seperti dibawah ini.


use Faker\Generator as Faker;

$factory->define(\App\CategoryModel::class, function (Faker $faker) {
return [
'name' => $faker->words(3, true)
];
});

Kita akan membuat namanya dengan kata acak sebanyak 3 kata dan karena defaultnya adalah array maka kita ubah menjadi teks panjang dengan menaruh parameter true pada parameter kedua.

Nah pertama kita akan melakukan uji coba terhadap data produk yang dimasukkan, silahkan teman-teman lakukan split tab aja agar enak ngodingnya.

Tampilan split tab

Tutup saja tab project sehingga menghasilkan dua tab saja agar enak ngodingnya.

Ingat, dalam membuat unit test agar enak cukup buka dua tiga tab saja, yaitu:

  1. Controller yang diuji coba.
  2. Unit Test
  3. Routes

Setelah itu baru deh enak ngebuat unit testnya.

Sekarang kita masukkin kode pertama kita:

/**
*
@test
*/
public function it_stores_data()
{
//TODO: code inside here --Created by Kiddy

//Membuat objek user yang otomatis menambahkannya ke database.
$user = factory(User::class)->create();

//Membuat objek category yang otomatis menambahkannya ke database.
$category = factory(CategoryModel::class)->create();

//Acting as berfungsi sebagai autentikasi, jika kita menghilangkannya maka akan error.
$response = $this->actingAs($user)
//Hit post ke method store, fungsinya ya akan lari ke fungsi store.
->post(route('product.store'), [
//isi parameter sesuai kebutuhan request
'name' => $this->faker->words(3, true),
'cat' => $category->id,
'quantity' => $this->faker->randomNumber(3),
'buy_price' => $this->faker->randomNumber(6),
'sell_price' => $this->faker->randomNumber(6),
]);

//Tuntutan status 302, yang berarti redirect status code.
$response->assertStatus(302);

//Tuntutan bahwa abis melakukan POST URL akan dialihkan ke URL product atau routenya adalah product.index
$response->assertRedirect(route('product.index'));
}

Jangan lupa untuk import classnya termasuk dengan fakernya, tambahkan kode ini dipaling atas fungsi utama.

use WithFaker;

WithFaker function

Faker gunanya akan mempermudah kita mendapatkan kata acak daripada kita capek-capek buat sendiri.

Setelah itu ayo coba jalanin dengan command dibawah ini:

phpunit tests/Feature/Http/Controllers/ProductControllerTest.php

Apa hasilnya?

PHPUnit successful test

Bingo! Green is my favorite color at Test-Driven Development, we hate RED so much hahahaha.

Ok, now we’re start to going more crazy. Saatnya kita melakukan uji coba dengan versi “ngawur” alias versi aneh-aneh hahaha, gimana caranya? Gampang! Cukup buat method test baru dengan hasil yang kita tau bakalan error tapi harus sesuai assertion atau tuntutan kita errornya.

Coba nih kita berpikir gimana kalo salah satu parameter request kita errorkan? Kira-kira apa yang terjadi ya? Misalkan parameter quantity kita ganti jadi qty pasti error, tapi apa sesuai dengan assertion kita? Coba yuk tambahkan satu method baru.

/**
*
@test
*/
public function it_stores_data_but_using_invalid_key_quantity()
{
//TODO: code inside here --Created by Kiddy

$user = factory(User::class)->create();
$category = factory(CategoryModel::class)->create();

$response = $this->actingAs($user)
->post(route('product.store'), [
'name' => $this->faker->words(3, true),
'cat' => $category->id,
'qty' => $this->faker->randomNumber(3),
'buy_price' => $this->faker->randomNumber(6),
'sell_price' => $this->faker->randomNumber(6),
]);

$response->assertStatus(302);
$response->assertRedirect(route('product.index'));
}

Setelah itu coba deh jalanin.

Error assertion

Bingo! Warna menyebalkan muncul, sekiranya kenapa ya bisa gitu? Tentu aja karena parameter quantity kita ganti menjadi qty, tapi kenapa actualnya kok dia lari ke halaman index?

Karena gini temen-temen, coba temen-temen perhatikan kode di ProductController fungsi store.

Store function

Temen-temen lihat baris yang saya sorot? Exactly! Itu adalah validasi dari quantity yang diharapkan ada. Unit test sebelumnya yang kita buat itu otomatis melakukan redirect->back(), alhasil kita jadi pergi ke index. Cara mengatasinya gimana? Gampang pisan kalo kata orang Bandung mah. Ganti kode yang tadi jadi kode dibawah.


namespace Tests\Feature\Http\Controllers;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ProductControllerTest extends TestCase
{
/**
* A basic feature test example.
*
*
@return void
*/
public function testExample()
{
$response = $this->get('/');

$response->assertStatus(200);
}
}
0

Kita pake fungsi from yang membuat simulasi seolah-olah kita sedang berada di route atau halaman tersebut. Sehingga kalo dia error otomatis akan dikembalikan ke halaman tersebut, sesuai deh sama assertion kita.

Jalanin lagi euy, sekarang gimana hasilnya?

Sucessful Assertion on Laravel Unit HTTP Test

Fuih! I love that color! Assertion kita berhasil sesuai kebutuhan kita!

Nah sekarang kita coba yang agak gila lagi, gimana kalo misalnya quantity kita masukkin huruf ya? Masuk ngga ya? Jelas ngga masuk sih secara logika kita, soalnya di databasenya tipe quantity kan Integer. Tapi itu baru secara logika manusia loh, kita tetep harus nyuruh komputer buat nyobain assertion kita.

Coba yuk tambahin kode baru ini:


namespace Tests\Feature\Http\Controllers;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ProductControllerTest extends TestCase
{
/**
* A basic feature test example.
*
*
@return void
*/
public function testExample()
{
$response = $this->get('/');

$response->assertStatus(200);
}
}
1

Sekarang coba lurrr, kita liat hasilnya.

Sucessful Assertions PHP Unit Test

Ah bener kan tuh assertions gue berjalan lancar, kita bilang sama PHP Unit kalo assertion kita tuh bakalan Error 500 alias Internal Server Error kalo tipe data Integer malah dimasukin String 😆. Iyasih orang bodoh mana yang mau masukin String, tapi sebagai Programmer kita wajib uji coba semua kasus sampe berhasil sesuai ekspektasi loh!

Nah sekarang giliran kalian untuk nyoba-nyoba sendiri seperti coba aja masukkin title dengan menggunakan 40–60 kata kira-kira error ngga sih dan sesuai dengan assertions kalian atau tidak.