Section 9/161 menit
9. Parameterized Tests Lanjutan
9. Parameterized Tests Lanjutan
CustomTestStringConvertible
Saat test case gagal, Swift Testing menampilkan parameter dalam pesan error. Untuk tipe kustom, implementasikan CustomTestStringConvertible:
swift
struct PriceTestCase {
let amount: Decimal
let currency: String
let expectedFormatted: String
}
// Membuat pesan error lebih readable
extension PriceTestCase: CustomTestStringConvertible {
var testDescription: String {
"\(amount) \(currency) → \"\(expectedFormatted)\""
}
}
@Test("Format harga", arguments: [
PriceTestCase(amount: 10000, currency: "IDR", expectedFormatted: "Rp10.000"),
PriceTestCase(amount: 1500000, currency: "IDR", expectedFormatted: "Rp1.500.000"),
PriceTestCase(amount: 9.99, currency: "USD", expectedFormatted: "$9.99"),
PriceTestCase(amount: 0, currency: "IDR", expectedFormatted: "Rp0"),
])
func testPriceFormatting(_ testCase: PriceTestCase) {
let result = PriceFormatter.format(testCase.amount, currency: testCase.currency)
#expect(result == testCase.expectedFormatted)
// Jika gagal, pesan: "10000 IDR → "Rp10.000""
}
Zip Arguments — Kombinasi Parameter
swift
// Jalankan test dengan kombinasi parameter yang dipasangkan
@Test("Konversi unit", arguments: zip(
[1.0, 5.0, 100.0], // input
[1000.0, 5000.0, 100000.0] // expected output (meter ke milimeter)
))
func testUnitConversion(meters: Double, expectedMillimeters: Double) {
#expect(UnitConverter.metersToMillimeters(meters) == expectedMillimeters)
}
Cartesian Product — Semua Kombinasi
swift
// Semua kombinasi input × output (bukan pasangan)
@Test("Operasi aritmatika", arguments: [1, 2, 5], [10, 20, 50])
func testArithmeticOperations(multiplier: Int, base: Int) {
let result = Calculator.multiply(multiplier, base)
#expect(result == multiplier * base)
// Akan dijalankan 9 kali: (1,10), (1,20), (1,50), (2,10), ... (5,50)
}
Parameterized dari External Data
swift
// Load test cases dari JSON file
struct APITestCase: Codable, CustomTestStringConvertible {
let endpoint: String
let method: String
let expectedStatus: Int
var testDescription: String { "\(method) \(endpoint) → \(expectedStatus)" }
}
func loadAPITestCases() throws -> [APITestCase] {
let url = Bundle.module.url(forResource: "api_test_cases", withExtension: "json")!
let data = try Data(contentsOf: url)
return try JSONDecoder().decode([APITestCase].self, from: data)
}
// Parameterized dari file — pastikan load-nya tidak throw
@Test("API endpoint tests", arguments: try loadAPITestCases())
func testAPIEndpoints(_ testCase: APITestCase) async throws {
let response = try await APIClient.request(
endpoint: testCase.endpoint,
method: testCase.method
)
#expect(response.statusCode == testCase.expectedStatus)
}