Section 2/161 menit

2. Masalah yang Dipecahkan di Level Lanjutan

2. Masalah yang Dipecahkan di Level Lanjutan

Masalah 1: Callback-Based Code Tidak Bisa Di-test dengan #expect Biasa

Banyak API Apple menggunakan callback (delegate, completion handler, NotificationCenter) yang tidak bisa langsung di-assert dengan #expect.

swift
// ❌ TANPA Confirmation: test tidak menunggu callback — selalu pass palsu
@Test
func testImageDownload() async {
    let downloader = ImageDownloader()
    var receivedImage: UIImage?

    downloader.download(url: testURL) { image in
        receivedImage = image  // Dipanggil setelah test selesai!
    }

    // Test sudah selesai sebelum callback dipanggil
    #expect(receivedImage != nil)  // Selalu gagal atau selalu pass secara tidak deterministik
}
swift
// ✓ DENGAN Confirmation: test menunggu callback dengan jumlah yang tepat
@Test
func testImageDownload() async {
    let downloader = ImageDownloader()

    await confirmation("Image berhasil didownload") { confirm in
        downloader.download(url: testURL) { image in
            #expect(image != nil)
            confirm()  // Sinyal bahwa callback dipanggil
        }
    }
}

Masalah 2: Bug yang Diketahui Menyebabkan Test Gagal — Tidak Ada Cara Track

Di XCTest, bug yang diketahui biasanya di-comment atau di-skip tanpa tracking. Ini menyebabkan bug terlupakan.

swift
// ❌ TANPA withKnownIssue: bug di-comment — tidak ada tracking
@Test
func testEdgeCaseCalculation() {
    let result = Calculator.divide(10, by: 0)
    // XCTAssertEqual(result, 0)  // Di-comment karena bug #1234 belum fix
    // Tidak ada cara tahu kapan bug ini fix dan test harus di-uncomment
}
swift
// ✓ DENGAN withKnownIssue: bug terdokumentasi, test tetap berjalan
@Test
func testEdgeCaseCalculation() {
    withKnownIssue("Bug #1234: divide by zero returns NaN, expected 0") {
        let result = Calculator.divide(10, by: 0)
        #expect(result == 0)  // Test tetap berjalan, failure dicatat sebagai "known issue"
    }
    // Jika bug sudah diperbaiki, withKnownIssue akan melaporkan "known issue unexpectedly passed"
    // → sinyal otomatis bahwa bug sudah fix dan blok ini bisa dihapus
}

Masalah 3: Test yang Berjalan Paralel Menyebabkan Race Condition

Swift Testing menjalankan test secara paralel secara default. Test yang share mutable state akan menjadi flaky.

swift
// ❌ TANPA isolasi: state shared antara test yang berjalan paralel
var sharedCounter = 0  // Mutable global state

@Test
func testIncrementA() {
    sharedCounter += 1
    #expect(sharedCounter == 1)  // Flaky! testIncrementB mungkin sudah increment
}

@Test
func testIncrementB() {
    sharedCounter += 1
    #expect(sharedCounter == 1)  // Flaky!
}
swift
// ✓ DENGAN @Suite serialized: pastikan test berjalan serial jika butuh shared state
@Suite(.serialized)  // Semua test di suite ini berjalan serial
struct CounterTests {
    var counter = 0  // State per-suite — tidak shared antar paralel run

    @Test mutating func testIncrementA() {
        counter += 1
        #expect(counter == 1)  // Selalu benar
    }

    @Test mutating func testIncrementB() {
        counter = 0  // Reset untuk test ini
        counter += 1
        #expect(counter == 1)  // Selalu benar
    }
}