Section 3/121 menit

3. @Test dan @Suite — Dasar

3. @Test dan @Suite — Dasar

@Test

swift
import Testing

// Minimal: nama diambil dari nama fungsi
@Test
func addTwoNumbers() {
    let result = Calculator.add(2, 3)
    #expect(result == 5)
}

// Dengan display name kustom
@Test("Kalkulasi persentase dengan pembulatan")
func percentageCalculation() {
    let result = Calculator.percentage(of: 33.33, from: 100)
    #expect(result  33.33)  // custom operator atau approximate comparison
}

// Async test — native, tidak perlu expectation
@Test("Fetch user dari API")
func fetchUser() async throws {
    let user = try await UserService().fetch(id: "user_123")
    #expect(user.id == "user_123")
    #expect(!user.name.isEmpty)
}

// Test yang diharapkan gagal (known bug/todo)
@Test("Fitur X belum diimplementasi", .disabled("Menunggu backend API"))
func featureX() {
    // Test ini di-skip
}

@Suite

swift
// Suite mengelompokkan test yang terkait
// Bisa struct, class, atau enum — tidak harus inherit apapun!
@Suite("Authentication")
struct AuthTests {
    // Properti bisa diinisialisasi langsung — tidak perlu setUp()
    let service = AuthService(environment: .testing)
    
    @Test("Login dengan kredensial valid")
    func loginWithValidCredentials() async throws {
        let session = try await service.login(username: "ari", password: "secret123")
        #expect(session.isValid)
        #expect(session.userId == "user_123")
    }
    
    @Test("Login dengan password salah")
    func loginWithWrongPassword() async throws {
        await #expect(throws: AuthError.invalidCredentials) {
            try await service.login(username: "ari", password: "wrong")
        }
    }
    
    // Suite bersarang
    @Suite("Session Management")
    struct SessionTests {
        @Test("Session expire setelah timeout")
        func sessionExpires() async throws {
            // ...
        }
    }
}

Init/Deinit sebagai setUp/tearDown

swift
@Suite("Database Tests")
struct DatabaseTests {
    let db: TestDatabase
    
    // init() adalah setUp — dijalankan sebelum setiap test
    init() async throws {
        db = try await TestDatabase.create()
        try await db.migrate()
    }
    
    // deinit adalah tearDown — dijalankan setelah setiap test
    deinit {
        db.destroyAll()  // cleanup
    }
    
    @Test
    func insertUser() async throws {
        try await db.insert(User(name: "Ari"))
        let users = try await db.fetchAll(User.self)
        #expect(users.count == 1)
    }
}