Membangun Aplikasi Perbankan yang Aman: Menerapkan Fungsi Pinjaman dengan TDD
Pada tutorial sebelumnya, kita belajar bagaimana menulis tes untuk operasi CRUD untuk mengelola data pelanggan dalam aplikasi perbankan kita. Pada bagian ini, kita akan melanjutkan membangun aplikasi kita dengan menambahkan fungsi pinjaman, dengan fokus pada pengembangan yang digerakkan oleh pengujian (TDD) untuk memastikan kode kita kuat dan andal.
Pengembangan yang Digerakkan oleh Pengujian (TDD)
TDD adalah proses pengembangan di mana kita menulis tes sebelum menulis kode sebenarnya. Pendekatan ini memaksa kita untuk memikirkan bagaimana kode kita akan digunakan dan membantu menangkap kesalahan sejak awal siklus pengembangan.
Menerapkan Perhitungan Bunga Pinjaman dan Jumlah yang Harus Dibayarkan
Pertama, kita akan menerapkan tes untuk perhitungan bunga pinjaman dan perhitungan jumlah yang harus dibayarkan. Ini memastikan logika kita untuk perhitungan ini akurat.
1. Membuat Unit Test
Jalankan perintah berikut untuk membuat file unit test:
php artisan make:test LoanCalculatorTest --unit
Ini membuat kelas LoanCalculatorTest di bawah folder tests/Unit. Kita menggunakan flag --unit untuk menunjukkan bahwa ini adalah unit test, yang berfokus pada pengujian komponen individual dari aplikasi kita.
2. Menerapkan Logika Unit Test
Buka kelas LoanCalculatorTest dan tambahkan kode berikut:
<?php namespace Tests\Unit; use PHPUnit\Framework\TestCase; use App\Services\LoanCalculator; class LoanCalculatorTest extends TestCase { /** * @dataProvider loanData */ public function testCalculateInterestAmount(float $principal, float $rate, int $time, float $expectedInterest) { $calculator = new LoanCalculator(); $interest = $calculator->calculateInterestAmount($principal, $rate, $time); $this->assertEquals($expectedInterest, $interest); } /** * @dataProvider loanData */ public function testCalculateAmountPayable(float $principal, float $rate, int $time, float $expectedInterest, float $expectedPayable) { $calculator = new LoanCalculator(); $payable = $calculator->calculateAmountPayable($principal, $rate, $time); $this->assertEquals($expectedPayable, $payable); } public function loanData(): array { return [ [10000, 0.1, 1, 1000, 11000], [5000, 0.05, 2, 500, 5500], [20000, 0.08, 3, 4800, 24800], ]; } }
Kelas test ini menguji dua metode dari kelas LoanCalculator kita: calculateInterestAmount dan calculateAmountPayable.
- testCalculateInterestAmount: Menguji perhitungan bunga menggunakan berbagai jumlah pokok pinjaman, suku bunga, dan jangka waktu pinjaman. Ia menggunakan dataProvider yang disebut loanData untuk menyediakan berbagai skenario test.
- testCalculateAmountPayable: Menguji perhitungan jumlah yang harus dibayarkan, yang merupakan jumlah dari jumlah pokok dan bunga yang dihitung.
3. Membuat Kelas LoanCalculator
Karena test akan gagal karena kelas LoanCalculator belum ada, mari kita buat.
- Buat Folder Services: Arahkan ke folder app dan buat folder baru bernama Services.
- Buat File LoanCalculator.php: Di dalam folder Services, buat file bernama LoanCalculator.php dan tambahkan kode berikut:
<?php namespace App\Services; class LoanCalculator { public function calculateInterestAmount(float $principal, float $rate, int $time): float { return $principal * $rate * $time; } public function calculateAmountPayable(float $principal, float $rate, int $time): float { return $principal + $this->calculateInterestAmount($principal, $rate, $time); } }
Kelas ini mengimplementasikan metode calculateInterestAmount dan calculateAmountPayable, menggunakan rumus bunga sederhana: I = P * R * T.
4. Menjalankan Tes
Sekarang, jalankan tes menggunakan perintah berikut:
php artisan test --filter=LoanCalculatorTest
Anda harus melihat semua tes berhasil. Ini menunjukkan bahwa logika kita untuk menghitung bunga pinjaman dan jumlah yang harus dibayarkan berfungsi dengan benar.
Menerapkan Fitur Penerbitan Pinjaman dan Laporan
Selanjutnya, kita akan menerapkan kemampuan untuk menerbitkan pinjaman dan melihat laporan pinjaman, memastikan fitur ini diuji sepanjang proses pengembangan.
1. Membuat Test Fitur Pinjaman
Jalankan perintah berikut untuk membuat test fitur baru:
php artisan make:test LoanTest
Ini membuat kelas LoanTest di bawah folder tests/Feature. Test fitur digunakan untuk menguji interaksi yang lebih kompleks dengan aplikasi kita, seperti tindakan pengguna dan alur data.
2. Menguji Formulir Penerbitan Pinjaman
Buka kelas LoanTest dan tambahkan metode test berikut:
<?php namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; use App\Models\Customer; use App\Models\Loan; class LoanTest extends TestCase { use RefreshDatabase; public function testCanViewLoanIssuanceForm() { $customer = Customer::factory()->create(); $response = $this->get(route('loan.form', $customer->id)); $response->assertStatus(200); $response->assertSee('Issue Loan'); } // ... more test methods ... }
Test ini memeriksa apakah pengguna dapat mengakses formulir penerbitan pinjaman untuk pelanggan tertentu.
3. Menerapkan Formulir Penerbitan Pinjaman
Test akan gagal karena rute dan formulir belum ada. Mari kita buat.
- Buat Loan Controller: Jalankan perintah berikut untuk membuat controller baru:
php artisan make:controller LoanController
- Tambahkan Metode index ke Controller: Buka file LoanController.php dan tambahkan metode berikut:
<?php namespace App\Http\Controllers; use App\Models\Customer; use Illuminate\Http\Request; class LoanController extends Controller { public function index(Customer $customer) { return view('loans.issue-loan', compact('customer')); } // ... other methods ... }
Metode ini mengambil objek customer dan menampilkan view issue-loan.
- Buat View issue-loan: Di folder views, buat folder baru bernama loans. Di dalam folder ini, buat file baru bernama issue-loan.blade.php dan tambahkan kode berikut:
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">Issue Loan to {{ $customer->name }}</div> <div class="card-body"> <form action="{{ route('loan.issue', $customer->id) }}" method="POST"> @csrf <div class="form-group"> <label for="principal">Principal Amount:</label> <input type="number" class="form-control" id="principal" name="principal" required> </div> <div class="form-group"> <label for="rate">Interest Rate (%):</label> <input type="number" class="form-control" id="rate" name="rate" required> </div> <div class="form-group"> <label for="time">Loan Term (Months):</label> <input type="number" class="form-control" id="time" name="time" required> </div> <button type="submit" class="btn btn-primary">Issue Loan</button> </form> </div> </div> </div> </div> </div> @endsection
View ini membuat formulir penerbitan pinjaman dengan bidang input untuk jumlah pokok, suku bunga, dan jangka waktu pinjaman.
- Tambahkan Tombol Issue Loan ke Daftar Pelanggan: Buka view daftar pelanggan dan tambahkan baris berikut di dalam tag untuk kolom "Actions":
<td> <a href="{{ route('loan.form', $customer->id) }}" class="btn btn-primary" role="button">Issue Loan</a> </td>
- Tambahkan Rute: Buka file routes/web.php dan tambahkan rute berikut:
use App\Http\Controllers\LoanController; // ... other routes ... Route::get('/issue-loan/{id}',[LoanController::class, 'index'])->name('loan.form');
Rute ini memetakan URL issue-loan ke metode index dari LoanController, meneruskan ID pelanggan sebagai parameter.
4. Menjalankan Tes
Jalankan LoanTest menggunakan perintah berikut:
php artisan test --filter=LoanTest
Anda sekarang harus melihat testCanViewLoanIssuanceForm berhasil.
5. Menguji Penerbitan Pinjaman
Selanjutnya, kita akan menguji apakah pengguna dapat berhasil menerbitkan pinjaman. Tambahkan metode test berikut ke kelas LoanTest:
public function testCanIssueLoan() { $customer = Customer::factory()->create(); $principal = 10000; $rate = 0.1; $time = 12; $response = $this->actingAs($customer->user) ->post(route('loan.issue', $customer->id), [ 'principal' => $principal, 'rate' => $rate, 'time' => $time, ]); $response->assertRedirect(route('customers.index')); $this->assertDatabaseHas('loans', [ 'customer_id' => $customer->id, 'principal' => $principal, 'interest_rate' => $rate, 'loan_term' => $time, ]); }
Test ini memverifikasi bahwa pinjaman berhasil diterbitkan ke customer dan disimpan di database. Ia mensimulasikan pengiriman formulir dengan menggunakan metode post dan menegaskan bahwa pengguna dialihkan ke daftar customer setelah penerbitan berhasil.
6. Menerapkan Logika Penerbitan Pinjaman
Test akan gagal karena rute, metode store, dan model pinjaman belum diterapkan. Mari kita buat komponen ini.
- Perbarui Aksi Formulir: Buka view issue-loan.blade.php dan perbarui atribut aksi formulir sebagai berikut:
<form action="{{ route('loan.issue', $customer->id) }}" method="POST">
- Tambahkan Rute: Tambahkan rute berikut ke file routes/web.php:
Route::post('/issue-loan', [LoanController::class, 'store'])->name('loan.issue');
- Buat Migrasi Pinjaman: Jalankan perintah berikut untuk membuat migrasi untuk tabel loans:
php artisan make:migration create_loans_table
- Perbarui File Migrasi: Buka file migrasi dan perbarui dengan kode berikut:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateLoansTable extends Migration { public function up() { Schema::create('loans', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('customer_id'); $table->decimal('principal', 10, 2); $table->decimal('interest_rate', 4, 2); $table->integer('loan_term'); $table->decimal('interest_amount', 10, 2)->nullable(); $table->decimal('amount_payable', 10, 2)->nullable(); $table->timestamp('issued_at')->nullable(); $table->timestamps(); $table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade'); }); } public function down() { Schema::dropIfExists('loans'); } }
- Buat Model Pinjaman: Jalankan perintah berikut untuk membuat model pinjaman:
php artisan make:model Loan
- Perbarui Model Pinjaman: Buka file Loan.php dan perbarui dengan kode berikut:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Loan extends Model { use HasFactory; protected $fillable = [ 'customer_id', 'principal', 'interest_rate', 'loan_term', 'interest_amount', 'amount_payable', 'issued_at', ]; public function customer() { return $this->belongsTo(Customer::class); } }
- Tambahkan Metode store ke Controller: Tambahkan metode berikut ke file LoanController.php:
<?php namespace App\Http\Controllers; use App\Models\Customer; use App\Models\Loan; use App\Services\LoanCalculator; use Carbon\Carbon; use Illuminate\Http\Request; class LoanController extends Controller { // ... other methods ... public function store(Request $request, Customer $customer) { $validatedData = $request->validate([ 'principal' => 'required|numeric|min:1', 'rate' => 'required|numeric|min:0', 'time' => 'required|integer|min:1', ]); $calculator = new LoanCalculator(); $interestAmount = $calculator->calculateInterestAmount($validatedData['principal'], $validatedData['rate'] / 100, $validatedData['time']); $amountPayable = $calculator->calculateAmountPayable($validatedData['principal'], $validatedData['rate'] / 100, $validatedData['time']); $loan = Loan::create([ 'customer_id' => $customer->id, 'principal' => $validatedData['principal'], 'interest_rate' => $validatedData['rate'] / 100, 'loan_term' => $validatedData['time'], 'interest_amount' => $interestAmount, 'amount_payable' => $amountPayable, 'issued_at' => Carbon::now(), ]); return redirect()->route('customers.index'); } }
Metode ini memvalidasi data formulir, menghitung bunga dan jumlah yang harus dibayarkan, membuat catatan Loan baru di database, dan mengalihkan pengguna ke daftar customer.
7. Menjalankan Tes
Sekarang jalankan LoanTest lagi. Anda harus melihat kedua metode test berhasil, yang menunjukkan bahwa fitur penerbitan pinjaman kita berfungsi dengan benar.
8. Menguji View Laporan Pinjaman
Terakhir, kita akan menambahkan test untuk memeriksa apakah pengguna dapat melihat laporan pinjaman. Tambahkan metode berikut ke kelas LoanTest:
public function testCanViewLoanReport() { $response = $this->get(route('loan.report')); $response->assertStatus(200); $response->assertSee('Loan Report'); }
Test ini memeriksa apakah halaman laporan pinjaman dapat diakses dan ditampilkan dengan benar.
9. Menerapkan Fitur Laporan Pinjaman
Test ini akan gagal karena halaman laporan dan rute belum didefinisikan. Mari kita terapkan.
- Tambahkan Tombol untuk Melihat Laporan: Buka view daftar pelanggan dan tambahkan tombol berikut di atas tabel:
<a href="{{ route('loan.report') }}" class="btn btn-success">View Report</a>
- Buat Halaman Laporan: Di folder views/loans, buat file bernama loan-report.blade.php dan tambahkan kode berikut:
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">Loan Report</div> <div class="card-body"> <table class="table"> <thead> <tr> <th>Customer Name</th> <th>Principal Amount</th> <th>Interest Rate</th> <th>Loan Term (Months)</th> <th>Interest Amount</th> <th>Amount Payable</th> <th>Issued Date</th> </tr> </thead> <tbody> @foreach ($loans as $loan) <tr> <td>{{ $loan->customer->name }}</td> <td>{{ $loan->principal }}</td> <td>{{ $loan->interest_rate * 100 }}%</td> <td>{{ $loan->loan_term }}</td> <td>{{ $loan->interest_amount }}</td> <td>{{ $loan->amount_payable }}</td> <td>{{ $loan->issued_at->format('Y-m-d') }}</td> </tr> @endforeach </tbody> </table> </div> </div> </div> </div> </div> @endsection
View ini menampilkan tabel dengan informasi tentang semua pinjaman yang diterbitkan.
- Tambahkan Rute: Tambahkan rute berikut ke file routes/web.php:
Route::get('/view-report', [LoanController::class, 'view_report'])->name('loan.report');
- Tambahkan Metode view_report ke Controller: Tambahkan metode berikut ke file LoanController.php:
public function view_report() { $loans = Loan::with('customer')->get(); return view('loans.loan-report', compact('loans')); }
Metode ini mengambil semua pinjaman dan meneruskannya ke view loan-report.
10. Menjalankan Tes
Jalankan LoanTest lagi. Anda harus melihat ketiga tes berhasil.
Kesimpulan
Pada tutorial ini, kita telah menerapkan fungsi pinjaman dalam aplikasi perbankan kita menggunakan TDD. Dengan menulis tes sebelum menulis kode, kita memastikan bahwa setiap fitur berfungsi dengan benar dan bahwa kita tidak merusak fungsi yang ada. Pendekatan ini membantu kita membangun aplikasi yang lebih andal dan kuat, mengurangi risiko bug dan meningkatkan kualitas kode secara keseluruhan. Pada bagian terakhir dan terakhir dari seri ini, kita akan menerapkan otentikasi pengguna untuk membatasi akses ke aplikasi kita.
Posting Komentar