Testing Laravel: Testing Validasi Form
Bismillahirrahmanirrahim
Kita lanjutkan membuat validasi form input task. Mungkin teman-teman sudah melihat, ketika membuka aplikasi pada url /tasks
, kemudian langsung tekan tombol Create Task (submit form) tanpa mengisi field name
dan description
, kita dapatkan error seperti ini.
Error ini disebabkan karena kolom name
tidak boleh bernilai null saat diinput ke database. Sebagaimana file migration untuk table tasks
: xxxxx_create_tasks_table.php, name
dan description
tidak diset nullable. Error ini juga akan terjadi jika kolom description
kosong.
Solusinya, kita harus buat validasi form input task ini, untuk memastikan user menginput data dengan benar. Karena misi kita menerapkan TDD, maka kita juga buat testing sebelum membuat validasi form.
Di sini starting point saya berasal dari commit repo ini pada artikel sebelumnya. Teman-teman silakan teruskan project sendiri jika sudah mengikuti artikel ini dari awal.
Membuat Testing untuk menguji validasi form
Seperti biasa sebelum mulai kerja, kita pastikan semua testing passed.
# 1
$ vendor/bin/phpunit
OK (6 tests, 13 assertions)
Sip, kita lanjutkan. Buka file tests/Feature/ManageTasksTest.php
, tambahkan method test baru seperti berikut :
<?php
// Kelas ManageTasksTest.php
// ... user_can_create_a_task()
/** @test */
public function task_entry_must_pass_validation()
{
// Submit form untuk membuat task baru
// dengan field name description kosong
$this->post('/tasks', [
'name' => '',
'description' => '',
]);
// Cek pada session apakah ada error untuk field nama dan description
$this->assertSessionHasErrors(['name', 'description']);
}
Hasil: Error
Session missing key: errors
Failed asserting that false is true.
Penyebab
Belum muncul error (dari validasi) pada session, karena kita belum membuat validasi pada TasksController@store
.
Solusi
Tambahkan script validasi Laravel untuk field name
dan description
.
<?php
// TasksController
// ... method index
public function store()
{
request()->validate([
'name' => 'required|max:255',
'description' => 'required|max:255',
]);
Task::create(request()->only('name', 'description'));
return back();
}
# 2
$ vendor/bin/phpunit
OK (7 tests, 16 assertions)
Sip. Kita sudah dapat hijau lagi. Sekarang kita coba buka aplikasi dari browser.
Menampilkan error validasi form
Kita coba klik tombol Create Task (submit form). Nah, error SQL sebelumnya sudah hilang. Kita sudah redirect ke halaman sebelumnya, tetapi belum ada tampilan pesan (error) validasi form. Oke, kita tambahkan script untuk menampilkan error validasinya pada view tasks.index
.
<!-- ... -->
<div class="col-md-4">
<h2>New Task</h2>
@if (count($errors) > 0)
<div class="alert alert-danger">
<ul class="list-unstyled">
@foreach ($errors->all() as $error)
<li>{% raw" >}}{{ $error }}{% endraw" >}}</li>
@endforeach
</ul>
</div>
@endif
<form action="{% raw" >}}{{ url('tasks') }}{% endraw" >}}" method="post">
<!-- ... -->
</form>
</div>
<!-- ... -->
Simpan, kita kembali ke browser dan coba klik Create Task lagi. Seharusnya kita dapatkan tampilan seperti ini, pesan dari validasi form sudah muncul.
Sekarang kita coba jalankan PHPUnit, untuk memastikan tidak ada yang error/kerusakan dari perubahan barusan.
# 3
$ vendor/bin/phpunit
Ok, sampai di sini selesai penambahan fitur validasi untuk form Input Task.
Mungkin sebagian teman-teman ada yang bertanya, kenapa kita menggunakan $this->post()
saat menguji validasi form, bukan menggunakan $this->submitForm()
seperti saat testing input task.
Perbedaan “$this->submitForm()” dengan “$this->post()”
-
Pada
$this->submitForm()
Paket browserkit testing berinteraksi dengan halaman web, dia mendeteksi halaman web dengan bantuan DOM Crawler Symfony. Yaitu mencari komponen html berupa tagform
yang didalamnya ada tombol submit dengan tulisan Create Task, mencari input field bernamaname
dandescription
, kemudian melakukan submit form seolah-olah menekan tombol submit Create Task tadi. Method$this->submitForm()
ini juga dapat menerima respons saat aplikasi redirect ke halaman lain.Kekurangan dari method
$this->submitForm()
ini, dia tidak mendeteksi isi session Laravel. Sehingga pesan validasi form yang ingin kita cek (di testing) pada session Laravel tidak terlihat. (Mohon koreksi jika saya keliru paham tentang ini). -
Pada
$this->post()
Paket browserkit testing berinteraksi dengan HTTP Request langsung ke URL yang dituju (misal/tasks
) dengan methodpost
.Method
$this->post()
ini tidakperduliberinteraksi dengan halaman web, dia langsung mengirim request ke URL tujuan (dengan method yang sesuai). Method ini dapat berinteraksi dengan session Laravel, karenanya kita dapat melihat session yang berisi pesan (error) validasi form.Kekurangan dari method
$this->post()
ini, dia mengabaikan form yang kita buat di view. Ketika kita melakukan perubahan field di view, misal nama fielddescription
diubah menjadideskripsi_task
(tetapi pada testing tidak disesuaikan), method ini tidak perduli dengan perubahan itu (testing tetappassed
), karena dia langsung melakukan request ke URL yang dituju.Sedangkan method
$this->submitForm()
, dia akan berpengaruh terhadap perubahan ini. Testing akanfail
karena nama field di view berbeda dengan yang di script testing.BTW, selain
$this->post()
, ada juga$this->get()
,$this->patch()
,$this->put()
, dan$this->delete()
. Masing-masing method ini akan berinteraksi dengan method yang sesuai saat kita mendifinisikan Route pada fileroutes/web.php
, misalRoute::get()
,Route::post()
,Route::patch()
,Route::put()
, danRoute::delete()
.
Jadi antara kedua metode submit form tersebut, saya pribadi lebih sering menggunakan $this->submitForm()
dalam menguji sebuah fitur CRUD, karena dia beriteraksi dengan halaman web dan elemen-elemen form. Supaya ketika kita mengutak-atik form di view, tetapi lupa menyesuaikan testingnya, testing akan fail
(segera ketahuan). Jadi hasilnya lebih pasti dan meyakinkan. :)
Baik teman-teman, semoga artikel ini mudah dimengerti. Jika ada yang belum dipahami atau kurang jelas. Silakan disampaikan di komentar. Perubahan script di atas dapat dilihat pada commit repo ini.
Terima kasih sudah berkenan membaca.