Tutorial Unit Testing dengan Laravel 11 Pada Projek Toko Obat Online

Unit testing berperan penting dalam pengembangan aplikasi, termasuk dalam projek Toko Obat Online. Salah satu fitur krusial yang perlu diuji adalah Add to Cart.

Unit testing memastikan bahwa proses penambahan obat ke keranjang berjalan lancar tanpa ada kesalahan, serta menghindari penambahan stok yang melebihi jumlah stok tersedia.

Pada tutorial ini, kita akan melakukan pendekatan yang lebih terstruktur dengan memindahkan logika bisnis ke dalam service layer. Selain itu, kita juga akan melakukan validasi untuk memastikan bahwa stok obat tidak melebihi jumlah yang tersedia.

5 Tips Membuat Unit Testing dengan Laravel 11

1. Pisahkan Logika Bisnis dari Controller

Memisahkan logika bisnis dari controller adalah praktik terbaik untuk menjaga agar kode tetap bersih, terstruktur, dan mudah dikelola. Ini membuat controller berfungsi hanya sebagai perantara antara request dari user dan logika bisnis di dalam service.

Dengan memindahkan logika bisnis ke service, kita bisa dengan mudah mengelola dan menguji setiap fungsi tanpa terlalu banyak ketergantungan pada flow aplikasi utama.

Contoh:

Misalnya, kita memiliki fitur Add to Cart. Daripada menulis semua logika di controller, kita pindahkan logika tersebut ke service yang terpisah. Berikut adalah contohnya:

// CartService.php
<?php

namespace App\\\\Services;

use App\\\\Models\\\\Obat;
use Illuminate\\\\Support\\\\Facades\\\\Session;

class CartService
{
    public function addToCart($obatId, $quantity)
    {
        $obat = Obat::findOrFail($obatId);
        $cart = session()->get('cart', []);

        // Validasi stok yang tersedia
        if (isset($cart[$obatId])) {
            $newQuantity = $cart[$obatId]['quantity'] + $quantity;
            if ($newQuantity > $obat->stok) {
                throw new \\\\Exception('Jumlah yang diminta melebihi stok tersedia');
            }
            $cart[$obatId]['quantity'] = $newQuantity;
        } else {
            if ($quantity > $obat->stok) {
                throw new \\\\Exception('Jumlah yang diminta melebihi stok tersedia');
            }
            $cart[$obatId] = [
                'nama_obat' => $obat->nama_obat,
                'harga' => $obat->harga,
                'quantity' => $quantity,
            ];
        }

        session()->put('cart', $cart);

        return $cart;
    }
}

Pada controller, kita hanya perlu memanggil service ini tanpa memasukkan logika bisnis:

// CartController.php
<?php

namespace App\\\\Http\\\\Controllers;

use App\\\\Services\\\\CartService;
use Illuminate\\\\Http\\\\Request;

class CartController extends Controller
{
    protected $cartService;

    public function __construct(CartService $cartService)
    {
        $this->cartService = $cartService;
    }

    public function addToCart(Request $request, $id)
    {
        $validated = $request->validate([
            'quantity' => 'required|integer|min=1',
        ]);

        try {
            $this->cartService->addToCart($id, $validated['quantity']);
            return response()->json(['message' => 'Obat berhasil ditambahkan ke keranjang']);
        } catch (\\\\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
}

Dengan ini, controller menjadi lebih ringkas dan hanya fokus pada request handling.

2. Gunakan Factory untuk Data Palsu

Factory memungkinkan kita untuk membuat data uji dengan mudah, sehingga kita tidak perlu membuat data secara manual dalam setiap tes. Factory memudahkan pembuatan data seperti obat, pengguna, dan transaksi, yang membantu kita memastikan tes berjalan dengan data yang mirip dengan skenario nyata.

Contoh:

php artisan make:factory ObatFactory --model=Obat

Kemudian, buat factory untuk model Obat:

// database/factories/ObatFactory.php
<?php

namespace Database\\\\Factories;

use App\\\\Models\\\\Obat;
use Illuminate\\\\Database\\\\Eloquent\\\\Factories\\\\Factory;

class ObatFactory extends Factory
{
    protected $model = Obat::class;

    public function definition()
    {
        return [
            'nama_obat' => $this->faker->word(),
            'harga' => $this->faker->numberBetween(1000, 50000),
            'stok' => $this->faker->numberBetween(1, 100),
        ];
    }
}

Dengan factory ini, kita bisa membuat data obat dengan mudah di dalam tes:

$obat = Obat::factory()->create([
    'stok' => 10,
]);

3. Validasi Data dengan Baik

Validasi input sangat penting, terutama saat menangani stok atau jumlah barang. Pastikan data yang diterima valid dan tidak menimbulkan error yang bisa menyebabkan kerugian bisnis.

Contoh:

Dalam controller kita, lakukan validasi pada jumlah obat yang dimasukkan ke dalam keranjang:

$validated = $request->validate([
    'quantity' => 'required|integer|min=1',
]);

Kita juga bisa melakukan validasi tambahan di dalam service, misalnya mengecek apakah jumlah yang diminta melebihi stok yang tersedia:

if ($newQuantity > $obat->stok) {
    throw new \\\\Exception('Jumlah yang diminta melebihi stok tersedia');
}

4. Sederhanakan Unit Testing

Sederhanakan setiap unit test dengan memfokuskan pada satu fungsi kecil atau satu skenario. Jangan mencoba menguji beberapa hal sekaligus dalam satu tes karena itu bisa menyulitkan debugging jika terjadi kesalahan.

Contoh:

Untuk fitur Add to Cart, kita bisa membuat dua tes yang terpisah: satu untuk memastikan obat berhasil ditambahkan ke keranjang, dan satu lagi untuk memastikan stok tidak melebihi yang tersedia.

// tests/Feature/CartTest.php
public function test_add_to_cart_success()
{
    $obat = Obat::factory()->create(['stok' => 10]);

    $response = $this->postJson('/cart/add/'.$obat->id, ['quantity' => 5]);

    $response->assertStatus(200);
    $this->assertEquals(session('cart')[$obat->id]['quantity'], 5);
}

public function test_add_to_cart_exceeds_stock()
{
    $obat = Obat::factory()->create(['stok' => 5]);

    $response = $this->postJson('/cart/add/'.$obat->id, ['quantity' => 6]);

    $response->assertStatus(400);
    $response->assertJson(['error' => 'Jumlah yang diminta melebihi stok tersedia']);
}

5. Gunakan Database Transaksi untuk Isolasi Test

Laravel menyediakan fitur RefreshDatabase yang akan membersihkan dan mereset database setiap kali kita menjalankan tes. Ini memastikan bahwa tes tidak saling bergantung pada data yang tersisa dari tes sebelumnya, menjaga tes tetap independen dan hasilnya akurat.

Contoh:

// tests/Feature/CartTest.php
use Illuminate\\\\Foundation\\\\Testing\\\\RefreshDatabase;

class CartTest extends TestCase
{
    use RefreshDatabase;

    public function test_add_to_cart_success()
    {
        // Tes dengan refresh database
    }
}

Dengan menggunakan RefreshDatabase, setiap tes dimulai dengan kondisi database yang bersih, sehingga tidak ada data yang tertinggal dari tes sebelumnya yang dapat mempengaruhi hasil tes.

5 Fitur Utama yang Perlu Dibuat Unit Testing pada Projek Toko Obat Online

  • Add to Cart Tes untuk memastikan obat berhasil ditambahkan ke dalam keranjang tanpa melebihi jumlah stok.
  • Proses Checkout Tes untuk memastikan pengguna bisa melakukan checkout dengan informasi yang benar.
  • Manajemen Stok Obat Tes memastikan stok obat berkurang sesuai dengan transaksi yang dilakukan.
  • Autentikasi Pengguna Tes untuk memastikan bahwa hanya pengguna terdaftar yang bisa mengakses fitur tertentu.
  • Notifikasi Transaksi Tes untuk memastikan notifikasi dikirimkan setelah transaksi berhasil.

Tata Cara Melakukan Unit Testing pada Fitur Add to Cart

Berikut adalah langkah-langkah detail untuk membuat unit test pada fitur Add to Cart. Kita akan menggunakan service untuk menangani logika bisnis, memastikan validasi stok, dan membuat factory untuk data obat.

1. Membuat Factory untuk Model Obat

Langkah pertama adalah membuat factory untuk menghasilkan data obat palsu dalam jumlah banyak. Factory ini akan digunakan dalam unit testing.

php artisan make:factory ObatFactory --model=Obat

Buka file database/factories/ObatFactory.php, dan tambahkan konfigurasi berikut:

<?php

namespace Database\\\\Factories;

use App\\\\Models\\\\Obat;
use Illuminate\\\\Database\\\\Eloquent\\\\Factories\\\\Factory;

class ObatFactory extends Factory
{
    protected $model = Obat::class;

    public function definition()
    {
        return [
            'nama_obat' => $this->faker->word(),
            'harga' => $this->faker->numberBetween(1000, 100000),
            'stok' => $this->faker->numberBetween(1, 50),
        ];
    }
}

2. Membuat Service untuk Logika Add to Cart

Logika bisnis untuk fitur Add to Cart akan dipindahkan ke dalam service agar lebih mudah di-maintain. Service ini akan menangani validasi dan penambahan obat ke dalam keranjang.

Pertama, buat service dengan nama CartService.

php artisan make:service CartService

Lalu, tambahkan logika di dalam service ini.

<?php

namespace App\\\\Services;

use App\\\\Models\\\\Obat;
use Illuminate\\\\Support\\\\Facades\\\\Session;

class CartService
{
    public function addToCart($obatId, $quantity)
    {
        $obat = Obat::findOrFail($obatId);
        $cart = session()->get('cart', []);

        // Cek apakah stok mencukupi
        if (isset($cart[$obatId])) {
            $newQuantity = $cart[$obatId]['quantity'] + $quantity;

            if ($newQuantity > $obat->stok) {
                throw new \\\\Exception('Jumlah yang diminta melebihi stok tersedia');
            }

            $cart[$obatId]['quantity'] = $newQuantity;
        } else {
            if ($quantity > $obat->stok) {
                throw new \\\\Exception('Jumlah yang diminta melebihi stok tersedia');
            }

            $cart[$obatId] = [
                'nama_obat' => $obat->nama_obat,
                'harga' => $obat->harga,
                'quantity' => $quantity,
            ];
        }

        session()->put('cart', $cart);

        return $cart;
    }
}

3. Membuat Controller untuk Menghubungkan ke Service

Selanjutnya, kita akan membuat controller untuk menghubungkan request dari pengguna dengan service.

php artisan make:controller CartController

Di dalam CartController.php, tambahkan logika berikut:

<?php

namespace App\\\\Http\\\\Controllers;

use App\\\\Services\\\\CartService;
use Illuminate\\\\Http\\\\Request;

class CartController extends Controller
{
    protected $cartService;

    public function __construct(CartService $cartService)
    {
        $this->cartService = $cartService;
    }

    public function addToCart(Request $request, $id)
    {
        $validated = $request->validate([
            'quantity' => 'required|integer|min=1',
        ]);

        try {
            $this->cartService->addToCart($id, $validated['quantity']);
            return response()->json(['message' => 'Obat berhasil ditambahkan ke keranjang']);
        } catch (\\\\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
}

4. Membuat Unit Test untuk Fitur Add to Cart

Langkah terakhir adalah membuat unit test untuk menguji fitur Add to Cart. Kita akan menguji apakah obat berhasil ditambahkan dan stoknya tidak melebihi yang tersedia.

php artisan make:test CartTest

Di dalam tests/Feature/CartTest.php, tambahkan logika berikut:

<?php

namespace Tests\\\\Feature;

use App\\\\Models\\\\Obat;
use Illuminate\\\\Foundation\\\\Testing\\\\RefreshDatabase;
use Tests\\\\TestCase;

class CartTest extends TestCase
{
    use RefreshDatabase;

    public function test_add_to_cart_success()
    {
        // Buat data obat dengan factory
        $obat = Obat::factory()->create([
            'stok' => 10,
        ]);

        // Simulasi penambahan obat ke dalam keranjang dengan quantity 5
        $response = $this->postJson('/cart/add/'.$obat->id, [
            'quantity' => 5,
        ]);

        // Cek respon berhasil
        $response->assertStatus(200);

        // Cek apakah obat ditambahkan ke session
        $this->assertEquals(session('cart')[$obat->id]['quantity'], 5);
    }

    public function test_add_to_cart_exceeds_stock()
    {
        // Buat data obat dengan stok terbatas
        $obat = Obat::factory()->create([
            'stok' => 5,
        ]);

        // Simulasi penambahan obat dengan quantity yang melebihi stok
        $response = $this->postJson('/cart/add/'.$obat->id, [
            'quantity' => 6,
        ]);

        // Cek apakah respon error karena stok tidak mencukupi
        $response->assertStatus(400);
        $response->assertJson(['error' => 'Jumlah yang diminta melebihi stok tersedia']);
    }
}

Tes di atas memeriksa dua skenario:

  1. Penambahan obat ke keranjang dengan jumlah yang valid (stok mencukupi).
  2. Penambahan obat ke keranjang dengan jumlah yang melebihi stok, yang harus memicu error.

Jalankan tes menggunakan perintah:

php artisan test

Kesimpulan

Laravel terus menjadi salah satu framework PHP paling populer di kalangan developer, dan popularitasnya akan terus meningkat karena Laravel selalu memberikan update yang menarik. Setiap versi baru membawa fitur-fitur yang memudahkan pekerjaan developer, seperti integrasi dengan alat testing, pengelolaan database yang lebih efisien, serta berbagai peningkatan performa dan keamanan. Semua ini menjadikan Laravel sebagai pilihan yang tepat untuk membangun aplikasi web modern.

Bagi kamu yang ingin terus mengikuti perkembangan terbaru dari Laravel, pastikan untuk selalu memantau website BuildWithAngga. Mereka sering kali meng-update kelas-kelas gratis yang dilengkapi dengan studi kasus menarik, sehingga kamu bisa belajar langsung dari pengalaman nyata.

Tidak hanya itu, setiap kelas juga dipandu oleh mentor-mentor berpengalaman yang siap membantu kamu dalam proses belajar. Ditambah lagi, kamu mendapatkan akses ke kelas tersebut seumur hidup, jadi kamu bisa belajar kapan saja tanpa batas waktu.

Terus tingkatkan kemampuan coding-mu bersama BuildWithAngga dan jadilah developer yang siap menghadapi tantangan teknologi masa depan!