From 2cbe128a0896d4d64d84a2f8e6e8b9c92c095e99 Mon Sep 17 00:00:00 2001 From: dend <2023010715051@mhs.ubharajaya.ac.id> Date: Thu, 6 Nov 2025 22:41:12 +0700 Subject: [PATCH] Menambahkan Unit Testing Pada app/java/src/test[unitest/java/com.example.tiptime/BMICalculatorTest.kt --- README.md | 5 +- .../com.example.tiptime/BMICalculatorTest.kt | 411 ++++++++++++++++++ 2 files changed, 414 insertions(+), 2 deletions(-) create mode 100644 app/src/test/java/com.example.tiptime/BMICalculatorTest.kt diff --git a/README.md b/README.md index 1c2607f..fca6020 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ Starter dimodifikasi dan terinspirasi dari: https://developer.android.com/codelabs/basic-android-compose-calculate-tip#0 --- +Dibantu oleh [Claude AI](https://claude.ai): +-Untuk Mengatasi Nan +-Modifikasi Tampilan UI Dan UX ## 🔄 Changelog - Perubahan dari Awal sampai Akhir @@ -199,7 +202,5 @@ data class BMIResult( - [ ] Rekomendasi diet dan olahraga - [ ] Export hasil ke PDF - [ ] Multi-language support -- [ ] Dark mode toggle -- [ ] BMI ideal calculator berdasarkan usia dan gender --- \ No newline at end of file diff --git a/app/src/test/java/com.example.tiptime/BMICalculatorTest.kt b/app/src/test/java/com.example.tiptime/BMICalculatorTest.kt new file mode 100644 index 0000000..d86f118 --- /dev/null +++ b/app/src/test/java/com.example.tiptime/BMICalculatorTest.kt @@ -0,0 +1,411 @@ +package com.example.tiptime + +import org.junit.Test +import org.junit.Assert.* +import org.junit.Before + +/** + * Unit Testing untuk BMI Calculator + * + * NPM: [202310715051] + * Nama: [Dendi Yogia Pratama] + */ + +class BMICalculatorTest { + + // Test Data Class BMIResult + @Test + fun `BMIResult should store values correctly`() { + val result = BMIResult( + bmiValue = 22.5, + category = "Normal weight", + isValid = true, + errorMessage = "" + ) + + assertEquals(22.5, result.bmiValue, 0.01) + assertEquals("Normal weight", result.category) + assertTrue(result.isValid) + assertEquals("", result.errorMessage) + } + + @Test + fun `BMIResult should handle invalid state`() { + val result = BMIResult( + bmiValue = 0.0, + category = "", + isValid = false, + errorMessage = "Invalid input" + ) + + assertFalse(result.isValid) + assertEquals("Invalid input", result.errorMessage) + } + + // Test BMI Category Function + @Test + fun `getBMICategory should return Underweight for BMI less than 18-5`() { + assertEquals("Underweight", getBMICategory(15.0)) + assertEquals("Underweight", getBMICategory(18.0)) + assertEquals("Underweight", getBMICategory(18.4)) + } + + @Test + fun `getBMICategory should return Normal weight for BMI 18-5 to 24-9`() { + assertEquals("Normal weight", getBMICategory(18.5)) + assertEquals("Normal weight", getBMICategory(20.0)) + assertEquals("Normal weight", getBMICategory(24.9)) + } + + @Test + fun `getBMICategory should return Overweight for BMI 25 to 29-9`() { + assertEquals("Overweight", getBMICategory(25.0)) + assertEquals("Overweight", getBMICategory(27.5)) + assertEquals("Overweight", getBMICategory(29.9)) + } + + @Test + fun `getBMICategory should return Obese for BMI 30 and above`() { + assertEquals("Obese", getBMICategory(30.0)) + assertEquals("Obese", getBMICategory(35.0)) + assertEquals("Obese", getBMICategory(40.0)) + } + + // Test SI Units BMI Calculation + @Test + fun `calculateBMI should calculate correctly for SI units - Normal weight`() { + val result = calculateBMI(170.0, 65.0, false) + + assertTrue(result.isValid) + assertEquals(22.49, result.bmiValue, 0.01) + assertEquals("Normal weight", result.category) + } + + @Test + fun `calculateBMI should calculate correctly for SI units - Underweight`() { + val result = calculateBMI(175.0, 55.0, false) + + assertTrue(result.isValid) + assertEquals(17.96, result.bmiValue, 0.01) + assertEquals("Underweight", result.category) + } + + @Test + fun `calculateBMI should calculate correctly for SI units - Overweight`() { + val result = calculateBMI(160.0, 70.0, false) + + assertTrue(result.isValid) + assertEquals(27.34, result.bmiValue, 0.01) + assertEquals("Overweight", result.category) + } + + @Test + fun `calculateBMI should calculate correctly for SI units - Obese`() { + val result = calculateBMI(165.0, 85.0, false) + + assertTrue(result.isValid) + assertEquals(31.22, result.bmiValue, 0.01) + assertEquals("Obese", result.category) + } + + // Test USC Units BMI Calculation + @Test + fun `calculateBMI should calculate correctly for USC units - Normal weight`() { + val result = calculateBMI(67.0, 143.0, true) + + assertTrue(result.isValid) + assertEquals(22.39, result.bmiValue, 0.01) + assertEquals("Normal weight", result.category) + } + + @Test + fun `calculateBMI should calculate correctly for USC units - Underweight`() { + val result = calculateBMI(69.0, 120.0, true) + + assertTrue(result.isValid) + assertEquals(17.72, result.bmiValue, 0.01) + assertEquals("Underweight", result.category) + } + + @Test + fun `calculateBMI should calculate correctly for USC units - Overweight`() { + val result = calculateBMI(63.0, 154.0, true) + + assertTrue(result.isValid) + assertEquals(27.31, result.bmiValue, 0.01) + assertEquals("Overweight", result.category) + } + + @Test + fun `calculateBMI should calculate correctly for USC units - Obese`() { + val result = calculateBMI(65.0, 200.0, true) + + assertTrue(result.isValid) + assertEquals(33.29, result.bmiValue, 0.01) + assertEquals("Obese", result.category) + } + + // Test Input Validation - SI Units + @Test + fun `validateBMIInput should reject zero height for SI units`() { + val (isValid, message) = validateBMIInput(0.0, 70.0, false) + + assertFalse(isValid) + assertEquals("Tinggi harus lebih dari 0", message) + } + + @Test + fun `validateBMIInput should reject negative height for SI units`() { + val (isValid, message) = validateBMIInput(-10.0, 70.0, false) + + assertFalse(isValid) + assertEquals("Tinggi harus lebih dari 0", message) + } + + @Test + fun `validateBMIInput should reject height below 50cm for SI units`() { + val (isValid, message) = validateBMIInput(45.0, 70.0, false) + + assertFalse(isValid) + assertEquals("Tinggi terlalu rendah (minimum 50cm)", message) + } + + @Test + fun `validateBMIInput should reject height above 300cm for SI units`() { + val (isValid, message) = validateBMIInput(350.0, 70.0, false) + + assertFalse(isValid) + assertEquals("Tinggi tidak wajar (maksimum 300cm)", message) + } + + @Test + fun `validateBMIInput should reject zero weight for SI units`() { + val (isValid, message) = validateBMIInput(170.0, 0.0, false) + + assertFalse(isValid) + assertEquals("Berat harus lebih dari 0", message) + } + + @Test + fun `validateBMIInput should reject weight below 20kg for SI units`() { + val (isValid, message) = validateBMIInput(170.0, 15.0, false) + + assertFalse(isValid) + assertEquals("Berat terlalu rendah (minimum 20kg)", message) + } + + @Test + fun `validateBMIInput should reject weight above 500kg for SI units`() { + val (isValid, message) = validateBMIInput(170.0, 550.0, false) + + assertFalse(isValid) + assertEquals("Berat tidak wajar (maksimum 500kg)", message) + } + + @Test + fun `validateBMIInput should accept valid SI units`() { + val (isValid, message) = validateBMIInput(170.0, 70.0, false) + + assertTrue(isValid) + assertEquals("", message) + } + + // Test Input Validation - USC Units + @Test + fun `validateBMIInput should reject zero height for USC units`() { + val (isValid, message) = validateBMIInput(0.0, 150.0, true) + + assertFalse(isValid) + assertEquals("Height must be greater than 0", message) + } + + @Test + fun `validateBMIInput should reject height below 20 inches for USC units`() { + val (isValid, message) = validateBMIInput(15.0, 150.0, true) + + assertFalse(isValid) + assertEquals("Height too low (minimum 20 inches)", message) + } + + @Test + fun `validateBMIInput should reject height above 120 inches for USC units`() { + val (isValid, message) = validateBMIInput(130.0, 150.0, true) + + assertFalse(isValid) + assertEquals("Height unrealistic (maximum 120 inches)", message) + } + + @Test + fun `validateBMIInput should reject weight below 44 lbs for USC units`() { + val (isValid, message) = validateBMIInput(65.0, 40.0, true) + + assertFalse(isValid) + assertEquals("Weight too low (minimum 44 lbs)", message) + } + + @Test + fun `validateBMIInput should reject weight above 1100 lbs for USC units`() { + val (isValid, message) = validateBMIInput(65.0, 1200.0, true) + + assertFalse(isValid) + assertEquals("Weight unrealistic (maximum 1100 lbs)", message) + } + + @Test + fun `validateBMIInput should accept valid USC units`() { + val (isValid, message) = validateBMIInput(67.0, 150.0, true) + + assertTrue(isValid) + assertEquals("", message) + } + + // Test BMI Category Info + @Test + fun `getBMICategoryInfo should return correct info for Underweight`() { + val info = getBMICategoryInfo("Underweight") + assertTrue(info.contains("kurang dari ideal")) + } + + @Test + fun `getBMICategoryInfo should return correct info for Normal weight`() { + val info = getBMICategoryInfo("Normal weight") + assertTrue(info.contains("Selamat")) + assertTrue(info.contains("ideal")) + } + + @Test + fun `getBMICategoryInfo should return correct info for Overweight`() { + val info = getBMICategoryInfo("Overweight") + assertTrue(info.contains("berlebih")) + } + + @Test + fun `getBMICategoryInfo should return correct info for Obese`() { + val info = getBMICategoryInfo("Obese") + assertTrue(info.contains("berlebih")) + assertTrue(info.contains("dokter")) + } + + // Test BMI Category Color + @Test + fun `getBMICategoryColor should return correct colors`() { + assertNotNull(getBMICategoryColor("Underweight")) + assertNotNull(getBMICategoryColor("Normal weight")) + assertNotNull(getBMICategoryColor("Overweight")) + assertNotNull(getBMICategoryColor("Obese")) + } + + // Test Category Emoji + @Test + fun `getCategoryEmoji should return correct emojis`() { + assertEquals("⚠️", getCategoryEmoji("Underweight")) + assertEquals("✅", getCategoryEmoji("Normal weight")) + assertEquals("⚡", getCategoryEmoji("Overweight")) + assertEquals("🔴", getCategoryEmoji("Obese")) + assertEquals("❓", getCategoryEmoji("Unknown")) + } + + // Test Format BMI Result + @Test + fun `formatBMIResult should format valid result correctly`() { + val result = BMIResult(22.486, "Normal weight", true, "") + val formatted = formatBMIResult(result) + assertTrue(formatted.contains("22") || formatted.contains("22,5")) + } + + @Test + fun `formatBMIResult should return error message for invalid result`() { + val result = BMIResult(0.0, "", false, "Error message") + val formatted = formatBMIResult(result) + assertEquals("Error message", formatted) + } + + // Edge Cases + @Test + fun `calculateBMI should handle boundary value BMI 18-5 exactly`() { + // Height and weight that should give BMI exactly 18.5 + val result = calculateBMI(175.0, 56.66, false) + assertTrue(result.bmiValue >= 18.4 && result.bmiValue <= 18.6) + } + + @Test + fun `calculateBMI should handle boundary value BMI 25-0 exactly`() { + // Height and weight that should give BMI exactly 25.0 + val result = calculateBMI(170.0, 72.25, false) + assertTrue(result.bmiValue >= 24.9 && result.bmiValue <= 25.1) + } + + @Test + fun `calculateBMI should handle boundary value BMI 30-0 exactly`() { + // Height and weight that should give BMI exactly 30.0 + val result = calculateBMI(170.0, 86.7, false) + assertTrue(result.bmiValue >= 29.9 && result.bmiValue <= 30.1) + } + + // Integration Tests + @Test + fun `full flow SI units should work correctly`() { + val height = 175.0 + val weight = 70.0 + + // Validate + val (isValid, _) = validateBMIInput(height, weight, false) + assertTrue(isValid) + + // Calculate + val result = calculateBMI(height, weight, false) + assertTrue(result.isValid) + assertEquals("Normal weight", result.category) + + // Format + val formatted = formatBMIResult(result) + assertTrue(formatted.isNotEmpty()) + + // Get info + val info = getBMICategoryInfo(result.category) + assertTrue(info.isNotEmpty()) + } + + @Test + fun `full flow USC units should work correctly`() { + val height = 69.0 + val weight = 154.0 + + // Validate + val (isValid, _) = validateBMIInput(height, weight, true) + assertTrue(isValid) + + // Calculate + val result = calculateBMI(height, weight, true) + assertTrue(result.isValid) + assertTrue(result.category.isNotEmpty()) + + // Format + val formatted = formatBMIResult(result) + assertTrue(formatted.isNotEmpty()) + } + + @Test + fun `calculateBMI should return invalid result for invalid input`() { + val result = calculateBMI(-10.0, 70.0, false) + + assertFalse(result.isValid) + assertTrue(result.errorMessage.isNotEmpty()) + assertEquals(0.0, result.bmiValue, 0.01) + } + + // Accuracy Tests + @Test + fun `BMI calculation should be accurate for SI units`() { + // Manual calculation: 75 / (1.80 * 1.80) = 23.148 + val result = calculateBMI(180.0, 75.0, false) + assertEquals(23.15, result.bmiValue, 0.01) + } + + @Test + fun `BMI calculation should be accurate for USC units`() { + // Manual calculation: 703 * (170 / (70 * 70)) = 24.39 + val result = calculateBMI(70.0, 170.0, true) + assertEquals(24.39, result.bmiValue, 0.01) + } +} \ No newline at end of file