cat swift/testing-swift-testing-xctest.md
Testing con Swift Testing e XCTest
Swift Testing e XCTest possono convivere: imparare test espressivi, parametrici e asincroni rende il package affidabile.
Swift ha una lunga storia con XCTest è un framework moderno chiamato Swift Testing. Nel codice attuale puoi incontrare entrambi.
Swift Testing offre API espressive, macro come #expect, test parametrizzati è un modello adatto al Swift moderno. XCTest resta ampiamente usato e supportato.
La cosa importante non è scegliere una bandiera: è scrivere test che proteggano comportamento reale.
Test con Swift Testing
import Testing
@testable import CouponCore
@Test
func percentualeRiduceTotale() throws {
let totale = Prezzo(10_000)!
let sconto = Sconto.percentuale(10)
let finale = try CouponEngine().totaleApplicando(sconto, a: totale)
#expect(finale == Prezzo(9_000))
}
#expect produce messaggi di fallimento più informativi rispetto a molti assert tradizionali.
Test parametrizzati
@Test(arguments: [
(10_000, 10, 9_000),
(5_000, 20, 4_000),
(1_000, 100, 0)
])
func scontoPercentuale(input: Int, percentuale: Int, expected: Int) throws {
let totale = Prezzo(input)!
let sconto = Sconto.percentuale(percentuale)
let finale = try CouponEngine().totaleApplicando(sconto, a: totale)
#expect(finale == Prezzo(expected))
}
I test parametrizzati riducono duplicazione senza perdere casi.
Test asincroni
@Test
func repositoryRestituisceCoupon() async throws {
let repository = CouponRepositoryInMemoria(coupon: [.welcome10])
let coupon = try await repository.couponDisponibili()
#expect(coupon.count == 1)
}
Il test può essere async throws, come il codice reale.
XCTest
Con XCTest:
import XCTest
@testable import CouponCore
final class CouponEngineTests: XCTestCase {
func testPercentualeRiduceTotale() throws {
let totale = Prezzo(10_000)!
let sconto = Sconto.percentuale(10)
let finale = try CouponEngine().totaleApplicando(sconto, a: totale)
XCTAssertEqual(finale, Prezzo(9_000))
}
}
XCTest è ancora molto diffuso. Saperlo leggere è importante.
Migrazione graduale
Puoi far convivere test XCTest è Swift Testing nello stesso package. Questo permette migrazioni graduali.
Non riscrivere tutti i test solo per moda. Aggiungi Swift Testing dove migliora chiarezza, parametrizzazione o diagnostica.
Testare errori
Swift Testing:
@Test
func couponSottoMinimoFallisce() async {
#expect(throws: ErroreCoupon.carrelloSottoMinimo(richiesto: 5_000, attuale: 2_000)) {
try CouponEngine().valida(coupon, nel: contesto)
}
}
Se il tuo errore è Equatable, puoi verificare il caso preciso.
Test e dominio
Testa comportamento, non implementazione privata.
Buono:
- un coupon valido si applica;
- un coupon sotto soglia fallisce;
- il totale non diventa negativo;
- una categoria mancante produce errore corretto.
Meno utile:
- verificare il nome di una variabile interna;
- testare helper privati direttamente;
- duplicare l’implementazione nel test.
Fixtures
Evita setup lunghi in ogni test:
extension Prodotto {
static let libro = Prodotto(...)
}
extension Coupon {
static let welcome10 = Coupon(...)
}
Le fixture devono essere leggibili e vicine al dominio.
Checklist
Per test professionali:
- test piccoli;
- nomi che descrivono comportamento;
- dati di test leggibili;
- errori verificati precisamente;
- test async dove serve;
- parametrizzazione per casi simili;
- nessuna dipendenza da rete reale nei test unitari;
- XCTest è Swift Testing possono convivere.
Esercizio
Scrivi test per CouponEngine:
- sconto percentuale;
- sconto fisso;
- totale mai negativo;
- minimo carrello non raggiunto;
- categoria mancante;
- tre casi parametrizzati per percentuali diverse.
Usa Swift Testing. Poi scrivi un test equivalente in XCTest per confrontare lo stile.