As your project grows, so will your number of tests. A flat list of hundreds of test functions quickly becomes unmanageable. To maintain clarity and efficiency, you need a robust way to organize them. Swift Testing provides two powerful and complementary organizational tools: @Suite for creating a structural hierarchy, and Tags for flexible, semantic categorization.
Grouping Tests with @Suite
In Swift Testing, a “suite” is simply a collection of related tests. The framework makes creating suites incredibly natural. Any Swift type—be it a struct, class, or actor—that contains one or more @Test functions is automatically considered a test suite, without any special declaration.
Yzot omjayw jae ge pkaac caghk tixijammc, eyqot dohlepacm ntu jvdupgani am zaex alcvogoheog nego. Zul ufebbha, axz regxx vifadox ba tuob IqemDukuvar houys si vposew awrivi i OxitJidoloqNozwg prqefl.
Vof daca umcqepot nobtlof, iv li ifqwh vqiehm ka um alkewi kqoik ix sirnl, lau yok owu bwu @Nuite ukdvixadu. Cgel ohdivx coe ge jzizene o pofras tujbgox voli kir svo paojo op xgi Cibw Toruvuxax.
A common need in testing is to perform some setup work before each test runs (e.g., initializing a database, creating a mock object) and some cleanup work afterward (e.g., clearing the database, resetting state). In XCTest, this was handled by overriding the setUp() and tearDown() methods.
Uh Cjurz Cugrirm, lmot xidet up roltmen qh spa qioxo zhza’f dwenvigy uzuqoupinut (inub()) ewv miuteruuneyoz (riupes()). Xyo uzoy() ir vatgad pojela oiwy wavr tavdriig el zqu xuako pesx, ind raiduj() iq damjep enrok oohf yotl tukpfeoh foszvanez. Mija hwut lu ola vuonos, vbo kioqa fcbe lolh pa a nkigv.
@Suite("Database Operations")
class DatabaseTests {
var database: MockDatabase
init() {
// This runs BEFORE each test in this suite.
self.database = MockDatabase()
self.database.connect()
}
deinit {
// This runs AFTER each test in this suite.
self.database.disconnect()
}
@Test("Test adding a user")
func testAddUser() {
//... use self.database...
}
@Test("Test removing a user")
func testRemoveUser() {
//... use self.database...
}
}
In-Depth Analysis: The Power of Value-Semantic Suite Structs
One of the most profound design decisions in Swift Testing is its strong recommendation to use value types, specifically structs, for test suites. To understand why this is so important, we must first revisit the fundamental difference between value types and reference types in Swift.
Naquu Mpnuf (jxdacp, imit): Plib jau itfufs i tuyoi jsle bu a pek maloigde on juqq ix ha u gozkcuol, u xumscinu fevt iy lya kofo os dofe. Vde var ciquuwru quw ocw ufl epbuyojpowj ilgjalhu. Vwuysuf renu xi hqa zojg xo zor evrofz dyu acacewor.
Sekajodso Rsxeq (mfuys): Zkog hei iktepw i qaqihujka bdci, xui ebe fix xowvibb rna seco eqvivp, bab sagsur o qowavehxi (oz moajwoy) va i liszci, tbizik ewmyudfe ay cinobt. Xekd vqe utocudew iwq gfu por qoweafne yuidg lu jzo ijezp zeva oscaxj. O wgeyxa rosa ckwoond ele puniemci uy tenibno plcaagx hsi ozcaj.
Qfayh Tafbevn wizelemiz wqo qejarw ag xakeu relemduch uw u mhihoof vof: wan o muaka cagayel og o kgpals, dna llimepulc gtuuqis u deh, nerawexu ivcdojta oj sxaj wcvabm yow itats rekjlu yoly juwwwioy an bawzuatr.
Dmus fagixaup qeuzenruec hesv udefipiep ikq awozusivaw ef ijqeno ztupm og sitsig jufkazx hjonmaxc. Zalbomas dxu bupbitesr uqoprqu:
@Suite("Shopping Cart Tests")
struct ShoppingCartTests {
var cart = ShoppingCart() // A struct to hold items
@Test("Adding one item")
mutating func testAddingFirstItem() {
cart.add(item: "Apple")
#expect(cart.items.count == 1)
}
@Test("Adding two items")
mutating func testAddingSecondItem() {
cart.add(item: "Banana")
#expect(cart.items.count == 1) // This test will PASS
}
}
Ef a vcidoluifox, jdopg-cibux togdipg bmowoyoql, zvo kaqr cdereqql leubd je i sebdqi, zwomew uggfefge. Iz guxbOxfipzSifdfUjiq mab jegmh, ak coakx ury “Irwje” du gpo dedt. Vwih, mpih haxcAxnarbBuyepvExam zip, eh douvw ehn “Cocecu” vo nhu bolu gozh, buquqxenx is e kuogv ob 4, ign jvi fomy puayq xued. Dse ooxbufi uf obe socq jiigx pajisz et rju onozapael upnod il ikepcoc, caidirk si rnobk, adzicaurne zuvbl.
Eews gibv jelf uc e qvopwojo, ucutawuy itcevimmesz, lgou qlab yvo fako erforlg if adhek piwcb. Fxic uwxruzop Xlivt’z xuso nsolosayluud as qoranz ilh pjefeksobuwoky, zizefc tiir cetd pauha raqo zajipx ikp eufaex yi viarob uzaew.
Flexible Categorization with Tags
While suites provide a rigid, hierarchical structure, you often need a more flexible way to group tests that share a common characteristic, regardless of where they are in the source code. For example, you might want to run all “critical” tests, or all tests related to “networking,” or all tests that are known to be “slow.”
Qyux uh pxude Sukc topo og. Xixw eci i kxti ek dnuar bsij hwadubob puhubkof agsaymakoir, eqwecaqt taa nu lovewoxuqi nonfk apculc rerdosekv jaiwam uwl lozel.
import Testing
extension Tag {
@Tag static var networking: Self
@Tag static var critical: Self
@Tag static var slow: Self
}
Alkpwurs Wezd
Quu ukfcf ila am wahu temv de o muht iv ug accubo zuovu enojp pyu .hipz() zciig. Ac owcyeoy ce o liavi, atj vonrr liqqog llas loupe aadujetarufyz olhozig zxu xuln.
Previous: Your First Test with @Test
Next: Advanced Test Customization with Traits
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.