๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

iOS/WWDC

WWDC24) Swift Testing ์†Œ๊ฐœ

๋ฐ˜์‘ํ˜•

 

- ๋›ฐ์–ด๋‚œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋ ค๋ฉด ํ’ˆ์งˆ, ์•ˆ์ •์„ฑ ์ค‘์š”

- ์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ์†Œํ”„ํŠธ์›จ์–ด ํ’ˆ์งˆ์„ ๋‹ฌ์„ฑํ•˜๊ณ  ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ์ž…์ฆ๋œ ๋ฐฉ๋ฒ•

 

swift testing์€ ์ƒˆ๋กœ์šด ์˜คํ”ˆ ์†Œ์Šค ํŒจํ‚ค์ง€๋กœ swift๋ฅผ ์‚ฌ์šฉํ•ด ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Œ.

 

 

ํ…Œ์ŠคํŠธ ์„ค๋ช…, ๊ตฌ์„ฑ, ์žฅ์•  ๋ฐœ์ƒ ์‹œ ๋Œ€์ฒ˜๋ฅผ ์œ„ํ•œ ์„ธ๋ถ€์ •๋ณด, ๋Œ€๊ทœ๋ชจ ์ฝ”๋“œ๋ฒ ์ด์Šค์— ๋งž๊ฒŒ ํ™•์žฅ ๊ฐ€๋Šฅ

 

๋™์‹œ์„ฑ ๋ฐ ๋งคํฌ๋กœ์™€ ๊ฐ™์€ ์ตœ์‹  ๊ธฐ๋Šฅ ๋„์ž…, Linux / Windows ๋“ฑ ๋ชจ๋“  ์ฃผ์š” ํ”Œ๋žซํผ ์ง€์›

 

1๏ธโƒฃ Swift Testing ๊ฐœ์š”

  • Swift Testing์€ Swift ์ „์šฉ์˜ ์ƒˆ๋กœ์šด ์˜คํ”ˆ ์†Œ์Šค ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, Xcode 16์— ๊ธฐ๋ณธ ํฌํ•จ๋จ.
  • ๋ชฉํ‘œ: ์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ํ’ˆ์งˆ๊ณผ ์•ˆ์ •์„ฑ์„ ์žฅ๊ธฐ์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›.
  • XCTest์™€๋Š” ๋‹ฌ๋ฆฌ Swift ์–ธ์–ด์˜ ํŠน์„ฑ๊ณผ ๋™์‹œ์„ฑ, ๋งคํฌ๋กœ, ํƒœ๊ทธ ๋“ฑ ์ตœ์‹  ๊ธฐ๋Šฅ์„ ํ™œ์šฉ.
  • Windows, Linux ๋“ฑ ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ์ง€์›. GitHub ์˜คํ”ˆ์†Œ์Šค๋กœ ๊ณต๊ฐœ ๊ฐœ๋ฐœ ์ค‘.

 

2๏ธโƒฃ Swift Testing์˜ ํ•ต์‹ฌ ๊ตฌ์„ฑ ์š”์†Œ 4๊ฐ€์ง€

- ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„ : ํ”„๋กœ์ ํŠธ์— ํ…Œ์ŠคํŠธ ๋ฒˆ๋“ค ๋Œ€์ƒ ์ถ”๊ฐ€ํ•˜๊ธฐ 

File > New > Target > Test ์„น์…˜์—์„œ Unit Testing Bundle ๊ฒ€์ƒ‰

 

Xcode 16์—์„œ ํ…Œ์ŠคํŠธ ์‹œ์Šคํ…œ์˜ ๊ธฐ๋ณธ ์„ ํƒ > Finish

 

- ์ฒซ ํ…Œ์ŠคํŠธ ์ž‘์„ฑํ•ด๋ณด๊ธฐ

๋ชจ๋“ˆ import > ์ „์—ญ ํ•จ์ˆ˜ ์ž‘์„ฑ > @Test ์†์„ฑ ์ถ”๊ฐ€

 

โœ… 1. ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜: @Test

  • ์ „์—ญ ํ•จ์ˆ˜, ์ •์  ํ•จ์ˆ˜, ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.
  • ๋น„๋™๊ธฐ(async), ์˜ˆ์™ธ(throws), ์•กํ„ฐ ๊ฒฉ๋ฆฌ๋„ ์ง€์›.
  • @Test("์„ค๋ช…") ํ˜•์‹์œผ๋กœ ์ด๋ฆ„ ์ง€์ • ๊ฐ€๋Šฅ.

- ํ…Œ์ŠคํŠธ์—์„œ ํ™•์ธํ•  ๊ฒƒ : ๋น„๋””์˜ค ํŒŒ์ผ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์˜ˆ์ƒ๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ 

ํ™•์ธํ•˜๋ ค๋Š” ๋น„๋””์˜ค์™€ ์˜ˆ์ƒ๋˜๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™”, ํ•ด๋‹น ๋ชจ๋“ˆ ๊ฐ€์ ธ์™€์•ผํ•จ - @testable import DestinationVideo

 

 

โœ… 2. ๊ธฐ๋Œ€์น˜ ๋งคํฌ๋กœ: #expect, #require

  • #expect๋Š” ํ‘œํ˜„์‹์„ ํ‰๊ฐ€ํ•˜๊ณ  ์‹คํŒจ ์‹œ ์ƒ์„ธ ์ •๋ณด ์ œ๊ณต (์†Œ์Šค์ฝ”๋“œ์™€ ํ•˜์œ„ ํ‘œํ˜„์‹ ๊ฐ’์„ ์บก์ฒ˜).
  • #require๋Š” ์กฐ๊ฑด ๋ถˆ์ถฉ์กฑ ์‹œ ํ…Œ์ŠคํŠธ ์กฐ๊ธฐ ์ข…๋ฃŒ.
  • ๋ชจ๋“  Swift ํ‘œํ˜„์‹ ์ง€์› (์—ฐ์‚ฐ์ž, ๋ฉ”์„œ๋“œ ๋“ฑ).
  • ์˜ˆ์‹œ: ๋งคํฌ๋กœ๋ฅผ ์‚ฌ์šฉํ•ด ๋น„๋””์˜ค ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธ
#expect(video.rating == .general)
#require let user = db.firstUser else { return }

- ๊ธฐ๋Œ€์น˜๋ฅผ ์ˆ˜ํ–‰ > ์˜ˆ์ƒ์กฐ๊ฑด์ด true์ธ์ง€ ํ™•์ธ

 

์‹คํŒจ : ๋ฉ”์‹œ์ง€ ํด๋ฆญ > show
๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ํŽผ์น˜๋ฉด ํ•ด๋‹น ์†์„ฑ์„ ๋น„๊ต ๊ฐ€๋Šฅ

- ๊ธฐ๊ฐ„ , ํ•ด์ƒ๋„ ํ•„๋“œ๊ฐ€ ๋ชจ๋‘ ์„œ๋กœ ๊ฐ™์ง€ ์•Š์Œ

- video ์œ ํ˜•์ด ์ดˆ๊ธฐํ™” ๋œ ํ›„ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ

- ๋ถ„ํ•  ํŽธ์ง‘๊ธฐ์—์„œ ๋น„๋””์˜ค ์ด๋‹ˆ์…œ๋ผ์ด์ €๋กœ ์ด๋™ํ•˜์—ฌ ์†์„ฑ์ด ํ• ๋‹น๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ํ•ด๊ฒฐํ•˜๊ธฐ

๋”๋ณด๊ธฐ

โœ… 1. ๋ถ„ํ•  ํŽธ์ง‘๊ธฐ ์—ด๊ธฐ ๋‹จ์ถ•ํ‚ค


์ˆ˜ํ‰ ๋ถ„ํ•  ํŽธ์ง‘๊ธฐ ์—ด๊ธฐ Control + Option + Command + T
์ˆ˜์ง ๋ถ„ํ•  ํŽธ์ง‘๊ธฐ ์—ด๊ธฐ Control + Command + โ†ฉ๏ธŽ Return (๋˜๋Š” ํŽธ์ง‘๊ธฐ ํƒญ์—์„œ ์˜ค๋ฅธ์ชฝ ํด๋ฆญ → Split Editor)
 

๋˜๋Š” ์ƒ๋‹จ ๋ฉ”๋‰ด์—์„œ Editor > Split Editor ์„ ํƒ๋„ ๊ฐ€๋Šฅ


โœ… 2. ํŒŒ์ผ ๊ฒ€์ƒ‰ (ํŒŒ์ผ ์ด๋ฆ„์œผ๋กœ ์ด๋™)

ํŒŒ์ผ ๊ฒ€์ƒ‰์ฐฝ ์—ด๊ธฐ Command + Shift + O
 

์ž…๋ ฅ์ฐฝ์— ํŒŒ์ผ ์ด๋ฆ„, ํƒ€์ž… ์ด๋ฆ„, ์‹ฌ๋ณผ ๋“ฑ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ

์ด๋‹ˆ์…œ๋ผ์ด์ €์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์†์„ฑ ํ• ๋‹น

 

ํ…Œ์ŠคํŠธ ์„ฑ๊ณต

 

 

#expect ๋งคํฌ๋กœ ์ถ”๊ฐ€ ์˜ˆ์‹œ )

== ์—ฐ์‚ฐ์ž, ์™ผ์ชฝ ์˜ค๋ฅธ์ชฝ ์บก์ฒ˜
.isEmpty , .contains ๋ฉ”์„œ๋“œ / ์˜ค๋ฅ˜๋ฅผ ๋ณด๋ฉด ์ˆซ์ž ๋ฐฐ์—ด์˜ ๋‚ด์šฉ์ด ์ž๋™์œผ๋กœ ํ‘œ์‹œ๋˜์–ด์žˆ์Œ

 

 

- ํ…Œ์ŠคํŠธ์—์„œ ์˜ˆ์ƒํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์•„ ์กฐ๊ธฐ ์ข…๋ฃŒํ•˜๊ณ  ์‹ถ์„ ๋•Œ ? #require ๋งคํฌ๋กœ

try ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ๊ณ , ํ‘œํ˜„์‹์ด false๋ฉด ์˜ค๋ฅ˜ ๋ฐœ์ƒ. > ํ…Œ์ŠคํŠธ ์‹คํŒจ

 

- ์˜ต์…”๋„ ๊ฐ’์„ ์•ˆ์ „ํ•˜๊ฒŒ ์–ธ๋ž˜ํ•‘ํ•˜๊ณ  ๊ฐ’์ด nil ์ธ ๊ฒฝ์šฐ์—๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ > ํ…Œ์ŠคํŠธ ์ค‘์ง€

 

#require ๋ฉ”ํฌ๋กœ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ปฌ๋ ‰์…˜์˜ .first ์†์„ฑ์— ์•ก์„ธ์Šคํ•˜๊ณ , ์š”์†Œ์˜ ์†์„ฑ์„ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์คŒ.

 

first ์†์„ฑ์€ ์„ ํƒ์‚ฌํ•ญ, ํ…Œ์ŠคํŠธ์˜ ๋‘๋ฒˆ์งธ ์ค„์€ ํ•ด๋‹น ๊ฐ’์— ์˜์กด. > ํ…Œ์ŠคํŠธ ์กฐ๊ธฐ ์ค‘์ง€ , ๋ž˜ํ•‘ ํ•ด์ œ๋œ ๊ฐ’์ด nil์ด๋ฉด ๊ณ„์†ํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ.

 

 

 

 

โœ… 3. ํŠน์„ฑ(Attribute)

  • ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ์„ค๋ช… ์ •๋ณด ์ถ”๊ฐ€, ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ๊ธฐ ๋˜๋Š” ์‹คํ–‰ ์—ฌ๋ถ€ ๋งž์ถคํ™”, ํ…Œ์ŠคํŠธ ๋™์ž‘ ๋ฐฉ์‹ ์ˆ˜์ •
  • ํ…Œ์ŠคํŠธ์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋˜๋Š” ๋™์ž‘ ์ œ์–ด๋ฅผ ๋ถ€์—ฌํ•˜๋Š” ๊ธฐ๋Šฅ.
  • ์‚ฌ์šฉ ์˜ˆ์‹œ: ํ‘œ์‹œ ์ด๋ฆ„, ๋น„ํ™œ์„ฑํ™”, ๋ฒ„๊ทธ ์ถ”์  ๋งํฌ, ์กฐ๊ฑด๋ถ€ ์‹คํ–‰ ๋“ฑ.
@Test("Test Video Rating", .bug("https://tracker/123"), .disabled("๊ธฐ๊ณ„ ๊ณ ์žฅ"))

@Test ์†์„ฑ์— ๋งž์ถคํ™”๋œ ํ‘œ์‹œ ์ด๋ฆ„์„ ์ „๋‹ฌ > ํ…Œ์ŠคํŠธ ๋‚ด๋น„๊ฒŒ์ดํ„ฐ์™€ Xcode์˜ ๋‹ค๋ฅธ ์œ„์น˜์— ํ‘œ์‹œ

 

 

- ๋‘๋ฒˆ์งธ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ : Xcode 16์— ๋‚ด์žฅ๋œ ํ…Œ์ŠคํŠธ ์Šค๋‹ˆํŽซ ์‚ฌ์šฉ > ๋นˆ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ์ถ”๊ฐ€

 

#expect ๋กœ contentRating์ด ๊ธฐ๋ณธ๊ฐ’์ด ๋˜๋„๋ก

 

-> ์ด ๋‘๊ฐ€์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ๊ทธ๋ฃนํ™” ํ•ด์„œ ํ”„๋กœ์ ํŠธ์—์„œ ๋” ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ๊ฒŒ

 

โœ… 4. ๋ชจ์Œ(Suite)

  • ๊ด€๋ จ ํ…Œ์ŠคํŠธ ๊ทธ๋ฃนํ™” ๊ตฌ์กฐ์ฒด.
  • @Suite ์†์„ฑ์œผ๋กœ ๋ช…์‹œ ๊ฐ€๋Šฅ (์•”์‹œ์  ์ธ์‹๋„ ๋จ).
  • init/deinit์—์„œ ํ…Œ์ŠคํŠธ ์ „ํ›„ ๋กœ์ง ์‹คํ–‰ ๊ฐ€๋Šฅ.
  • ๋ณ„๋„์˜ @Suite ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค @Testํ•จ์ˆ˜์— ๋Œ€ํ•ด ๋ณ„๋„๋กœ ์ƒ์„ฑ๋˜์–ด ์˜๋„์น˜ ์•Š์€ ์ƒํƒœ ๊ณต์œ  ๋ฐฉ์ง€.
  • ํ…Œ์ŠคํŠธ ์ƒํƒœ ๊ณต์œ  ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๊ตฌ์กฐ์ฒด ๊ถŒ์žฅ.

 

VideoTests๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋กœ ๋ž˜ํ•‘ > ๊ทธ๋ฃน์œผ๋กœ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๊ฐ€๋Šฅ.

 

์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Œ. ๊ฐ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ณณ์€ ํฌํ•จ๋œ ์ง‘ํ•ฉ ์œ ํ˜•์˜ ์ƒˆ ์ธ์Šคํ„ด์Šค์ด๋ฏ€๋กœ ๊ฐ๊ฐ ์ž์ฒด ๋น„๋””์˜ค ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ–๊ฒŒ ๋˜๋ฉฐ ์‹ค์ˆ˜๋กœ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ• ์ˆ˜ ์—†๊ฒŒ ๋จ.

 

3๏ธโƒฃ Swift Testing์˜ ํŠน์ง• ๋ฐ ์žฅ์ 

โœ… Swift ๋ฌธ๋ฒ• ์นœํ™”์  DSL

  • XCTAssertEqual ๋“ฑ ๋ณ„๋„ ์–ด์„ค์…˜ ํ•จ์ˆ˜ ์—†์ด๋„ ์ผ๋ฐ˜ Swift ํ‘œํ˜„์‹ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.

โœ… ์ƒ์„ธํ•œ ์‹คํŒจ ๋ฆฌํฌํŠธ

  • ์‹คํŒจ ์‹œ ์„œ๋ธŒ ํ‘œํ˜„์‹์˜ ๊ฐ’๊นŒ์ง€ ์ž๋™ ์ถœ๋ ฅ.
  • ์ฝ”๋“œ์—์„œ ๋””๋ฒ„๊น…์— ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋…ธ์ถœํ•จ.

โœ… ๋™์‹œ์„ฑ ์™„์ „ ํ†ตํ•ฉ

  • async/await, actor ๊ฒฉ๋ฆฌ ๋“ฑ์„ ์™„๋ฒฝ ์ง€์›.

โœ… ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ์‹คํ–‰ ์กฐ๊ฑด ์ œ์–ด

  • .enabled(if: someCondition) ๋˜๋Š” .disabled("์ด์œ ") ํŠน์„ฑ ์‚ฌ์šฉ.
  • CI/CD์—์„œ ์กฐ๊ฑด ๊ธฐ๋ฐ˜์œผ๋กœ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์—ฌ๋ถ€ ์ œ์–ด ๊ฐ€๋Šฅ.

โœ… ๋ฒ„์ „ ์ œํ•œ

  • @available ์‚ฌ์šฉ ๊ฐ€๋Šฅ. ํ…Œ์ŠคํŠธ๊ฐ€ ์ง€์› OS ๋ฒ„์ „ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์‹คํ–‰๋จ.

 

4๏ธโƒฃ  Common workflows : ์กฐ๊ฑด์ด ์žˆ๋Š” ํ…Œ์ŠคํŠธ 

์ผ๋ฐ˜์ ์ธ ์ž‘์—… ํ๋ฆ„

 

- ์กฐ๊ฑด์ด ์žˆ๋Š” ํ…Œ์ŠคํŠธ : ํŠน์ • ๊ธฐ๊ธฐ๋‚˜ ํ™˜๊ฒฝ ๋“ฑ ํŠน์ • ์ƒํ™ฉ์—์„œ๋งŒ ์‹คํ–‰ 

ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๋˜๊ธฐ ์ „ ํ‰๊ฐ€ํ•  ์กฐ๊ฑด ์ „๋‹ฌ, ์กฐ๊ฑด์ด false๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฑด๋„ˆ๋›ด ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ'

 

- ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰ ๋˜์ง€ ์•Š๊ฒŒ ํ•˜๋ ค๋ฉด ? ํ…Œ์ŠคํŠธ ๋น„ํ™œ์„ฑํ™”. ์ฃผ์„์ฒ˜๋ฆฌ๋ณด๋‹ค ์„ ํ˜ธ๋จ > ์ปดํŒŒ์ผ๋œ ํ…Œ์ŠคํŠธ ๋‚ด๋ถ€์˜ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜๊ธฐ ๋•Œ๋ฌธ.

( ํ…Œ์ŠคํŠธ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋œ ์ด์œ ๋ฅผ ์„ค๋ช…ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์ฃผ์„์€ ํ—ˆ์šฉ )

 

- ํ…Œ์ŠคํŠธ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜๋Š” ์ด์œ  : ๋ฒ„๊ทธ ์ถ”์  ์‹œ์Šคํ…œ์—์„œ ์ถ”์ ๋˜๋Š” ๋ฌธ์ œ ๋•Œ๋ฌธ์ธ ๊ฒฝ์šฐ 

- .bug(..) ํŠน์„ฑ์„ ํฌํ•จ ์‹œ์ผœ url๋กœ ๊ด€๋ จ ์ด์Šˆ ์ฐธ๊ณ  

- xcode 16 ์˜ ํ…Œ์ŠคํŠธ ๋ณด๊ณ ์„œ์—์„œ ํ•ด๋‹น ๋ฒ„๊ทธ ํŠน์„ฑ์„ ํ™•์ธํ•˜๊ณ  ํด๋ฆญํ•ด ํ•ด๋‹น url ํ™•์ธ ๊ฐ€๋Šฅ

 

- ํ…Œ์ŠคํŠธ์˜ ์ „์ฒด ๋ณธ๋ฌธ์„ ํŠน์ • OS๋ฒ„์ „์—์„œ๋งŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ

 

๋Ÿฐํƒ€์ž„์—์„œ ํ™•์ธํ•  ๋•Œ #available ์‚ฌ์šฉ ๋Œ€์‹  @available(...) ์†์„ฑ ์‚ฌ์šฉํ•ด๋ผ. > ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ…Œ์ŠคํŠธ์— OS๋ฒ„์ „ ์กฐ๊ฑด์ด ์žˆ๋‹ค๋Š” ๊ฑธ ์•Œ์ˆ˜ ์žˆ์–ด ์ด๋ฅผ ๊ฒฐ๊ณผ์— ๋” ์ •ํ™•ํ•˜๊ฒŒ ๋ฐ˜์˜.

 

5๏ธโƒฃ Common workflows : ํƒœ๊ทธ(Tag) ์‹œ์Šคํ…œ๊ณผ ํ…Œ์ŠคํŠธ ๊ทธ๋ฃนํ™”

- ๊ณตํ†ต๋œ ํŠน์ง•์„ ๊ฐ€์ง„ ํ…Œ์ŠคํŠธ๋ฅผ ์„œ๋กœ ๋‹ค๋ฅธ ๋ชจ์Œ์ด๋‚˜ ํŒŒ์ผ์— ์žˆ์–ด๋„ ์—ฐ๊ฒฐ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• 

โœ… ํƒœ๊ทธ ์„ ์–ธ ๋ฐ ์‚ฌ์šฉ

extension Tag {
  static let formatting = Tag("formatting")
}

@Test("ํ…Œ์ŠคํŠธ", .tag(.formatting))

โœ… ํšจ๊ณผ

  • ํ…Œ์ŠคํŠธ ๋‚ด๋น„๊ฒŒ์ดํ„ฐ์—์„œ ํƒœ๊ทธ๋กœ ๊ทธ๋ฃนํ™”ํ•˜๊ฑฐ๋‚˜ ์‹คํ–‰ ๊ฐ€๋Šฅ.
  • ํ…Œ์ŠคํŠธ ๊ณ„ํš์—์„œ ํŠน์ • ํƒœ๊ทธ ํฌํ•จ/์ œ์™ธ ์„ค์ • ๊ฐ€๋Šฅ.
  • ํƒœ๊ทธ ๊ธฐ๋ฐ˜ ๋ฆฌํฌํŠธ ๋ถ„์„ ๋ฐ ํŒจํ„ด ์ธ์‚ฌ์ดํŠธ ์ œ๊ณต.

 

- ๋งž์ถคํ˜• ํƒœ๊ทธ ํ• ๋‹น ๊ธฐ๋Šฅ : ํ…Œ์ŠคํŠธ ๋‚ด๋น„๊ฒŒ์ดํ„ฐ ํ•˜๋‹จ์— ๋ชจ๋“  ํƒœ๊ทธ๊ฐ€ ํ‘œ์‹œ

tag ํƒญ

 

 

- ์ผ๋ถ€ ๋ฐ์ดํ„ฐ ์„œ์‹ ์ง€์ • ๋กœ์ง์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๋Š” ํ…Œ์ŠคํŠธ 

ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€

- Video ์ •๋ณด์˜ ์„œ์‹ ์ง€์ •์— ๊ด€ํ•œ ๊ฒƒ > 2๊ฐœ ํ•˜์œ„ ๋ชจ์Œ์œผ๋กœ

- ์„œ์‹ ์ง€์ • ํƒœ๊ทธ๋ฅผ @Suite์œ„๋กœ ์˜ฌ๋ ค์„œ ํฌํ•จ๋œ ๋ชจ๋“  ํ…Œ์ŠคํŠธ์—์„œ ์ƒ์†๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

- ๊ณตํ†ต์ ์ด ์žˆ๋Š” ํ…Œ์ŠคํŠธ์— ํƒœ๊ทธ๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ

- ํŠน์ •ํ•œ ๊ธฐ๋Šฅ์ด๋‚˜ ํ•˜์œ„ ์‹œ์Šคํ…œ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋ชจ๋“  ํ…Œ์ŠคํŠธ์— ๊ณตํ†ต ํƒœ๊ทธ ์ ์šฉ

- ํŠน์ • ํƒœ๊ทธ๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ ํ• ์ˆ˜ ์žˆ์Œ

- test report์—์„œ ํ•„ํ„ฐ๋ง ๊ฐ€๋Šฅ

- ํƒœ๊ทธ ์ž์ฒด๋Š” ๋‹ค๋ฅธ ํŒŒ์ผ, ๋ชจ์Œ ๋˜๋Š” ๋Œ€์ƒ์˜ ํ…Œ์ŠคํŠธ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์Œ.

- ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ ๊ณต์œ  ๊ฐ€๋Šฅ 

 

 

swift testing : ํ…Œ์ŠคํŠธ ๊ฒŒํš์— ํŠน์ •ํ•œ ์ด๋ฆ„๋ณด๋‹ค ํƒœ๊ทธ๋ฅผ ํฌํ•จ์‹œํ‚ค๊ฑฐ๋‚˜ ์ œ์™ธํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์Œ

- ๋ชจ๋“  ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์Œ

- ๋Ÿฐํƒ€์ž„ ์กฐ๊ฑด : .enabled(if ...)

- ํƒœ๊ทธ ์‚ฌ์šฉ๋ฐฉ๋ฒ• -> ์‹ฌํ™” ์„ธ์…˜

 

 

6๏ธโƒฃ Common workflows : ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋œ ํ…Œ์ŠคํŠธ (Parameterized Test)

- ๋งค๋ฒˆ ๋‹ค๋ฅธ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ๋ฐ˜๋ณต

 

์˜ˆ์‹œ >  ๋‹ค์–‘ํ•œ ๋น„๋””์˜ค์—์„œ ์–ธ๊ธ‰๋˜๋Š” ๋Œ€๋ฅ™์˜ ์ˆ˜๋ฅผ ํ™•์ธํ•˜๋Š” ์—ฌ๋Ÿฌํ…Œ์ŠคํŠธ 

- ์ƒˆ๋กœ์šด videoLibrary ์ƒ์„ฑ > ๋น„๋””์˜ค๋ฅผ ์ด๋ฆ„์œผ๋กœ ์กฐํšŒ > #expect ๋งคํฌ๋กœ๋กœ ์–ธ๊ธ‰๋œ ๋Œ€๋ฅ™ ์ˆ˜ ํ™•์ธ

๋งค์šฐ ๋ฐ˜๋ณต์ , ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋น„๋””์˜ค๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์ค‘๋ณต๋œ ์ฝ”๋“œ ๋•Œ๋ฌธ์— ์œ ์ง€๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ์ง, ๊ฐ ํ…Œ์ŠคํŠธ์— ๊ณ ์œ ํ•œ ํ•จ์ˆ˜ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์•ผ๋˜๋Š”๋ฐ ์ด๋ฆ„์„ ์ฝ๊ธฐ๊ฐ€ ์–ด๋ ต๊ณ  ํ…Œ์ŠคํŠธํ•˜๋Š” ๋น„๋””์˜ค์˜ ์ด๋ฆ„๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

 

โœ… ๋ชฉ์ 

  • ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋กœ ๋‹ค์–‘ํ•œ ์ธ์ˆ˜์— ๋Œ€ํ•ด ๋ฐ˜๋ณต ์‹คํ–‰.
  • ์œ ์ง€๋ณด์ˆ˜์„ฑ ๊ฐœ์„ , ์ค‘๋ณต ์ œ๊ฑฐ, ์ธ์ˆ˜๋ณ„ ๋ณ‘๋ ฌ ์‹คํ–‰ ๊ฐ€๋Šฅ.

โœ… ์ž‘์„ฑ ๋ฐฉ๋ฒ•

@Test(arguments: ["Video1", "Video2"])
func testContinents(for videoName: String) {
    let video = library.lookup(name: videoName)
    #expect(video.mentionedContinents.count >= 1)
}

โœ… ์žฅ์ 

  • ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ ๊ฐœ๋ณ„ ์ธ์ˆ˜๋ณ„ ๊ฒฐ๊ณผ ์ œ๊ณต.
  • ์‹คํŒจํ•œ ์ธ์ˆ˜๋งŒ ๊ฐœ๋ณ„ ์žฌ์‹คํ–‰ ๊ฐ€๋Šฅ.
  • ๋””๋ฒ„๊น… ์‹œ ์ธ์ˆ˜ ํ™•์ธ ๋ฐ ์ค‘๋‹จ์  ์ง€์ • ์šฉ์ด.

 

 

1) ์„œ๋ช…์— ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€

ํ…Œ์ŠคํŠธ์— ์ „๋‹ฌํ•  ์ธ์ˆ˜ ํฌํ•จํ•ด์•ผ๋จ.

 

2) ์กฐํšŒํ•  ๋น„๋””์˜ค์˜ ์ด๋ฆ„์„ ์ „๋‹ฌ๋ฐ›์€ ์ธ์ˆ˜๋กœ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ

 

์—ฌ๋Ÿฌ ๋น„๋””์˜ค๋ฅผ ๋‹ค๋ฃธ : ์ด๋ฆ„์„ ์ผ๋ฐ˜ํ™”ํ•˜๊ธฐ > ์ด ํ…Œ์ŠคํŠธ์˜ ์ „์ฒด ์ด๋ฆ„์— ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ ˆ์ด๋ธ”์ด ํฌํ•จ๋จ.

 

- ์›ํ•˜๋Š” ๊ฒฝ์šฐ ์ธ์ž ์•ž์— ํ‘œ์‹œ ์ด๋ฆ„์ด๋‚˜ ๋‹ค๋ฅธ ํŠน์„ฑ์„ ์ „๋‹ฌํ•˜์—ฌ ์ด๋ฆ„ ์ง€์ • ๊ฐ€๋Šฅ 

 

ํ…Œ์ŠคํŠธ ์„ฑ๊ณต , ๋‚ด๋น„๊ฒŒ์ดํ„ฐ๊ฐ€ ๋ณ„๋„์˜ ํ…Œ์ŠคํŠธ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๊ทธ ์•„๋ž˜์˜ ๊ฐ ๊ฐœ๋ณ„ ๋น„๋””์˜ค ํ‘œ์‹œ

=> ์ธ์ˆ˜ ์ถ”๊ฐ€์™€ ํ…Œ์ŠคํŠธ ๋ฒ”์œ„ ํ™•์žฅ์ด ์‰ฌ์›Œ์ง.

 

๋‚˜๋จธ์ง€ ๋น„๋””์˜ค ์ถ”๊ฐ€ ํ›„ test ํ•จ์ˆ˜๋“ค ์‚ญ์ œ
์˜ค๋ฅ˜ > ์ธ์ˆ˜ ํด๋ฆญ > ์„ธ๋ถ€์ •๋ณด, ์‹คํŒจํ•œ ๊ธฐ๋Œ€์น˜ ๋ณผ ์ˆ˜ ์žˆ์Œ.

 

- ์‹คํŒจํ•œ ์ธ์ˆ˜๋งŒ ๋‹ค์‹œ > ์‹คํ–‰๋ฒ„ํŠผ์œผ๋กœ ๊ฐœ๋ณ„์ธ์ˆ˜ ์‹คํ–‰

- ๊ทธ์ „์— , ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ๋ถ€๋ถ„์— ์ค‘๋‹จ์  ์ถ”๊ฐ€

 

๋””๋ฒ„๊ฑฐ์— ํ‘œ์‹œ๋œ videoName์€ Scotland Coast -> ๋””๋ฒ„๊น… ์ง„ํ–‰ ํ•˜์—ฌ ์‹คํŒจ ์›์ธ ๋ณด๊ธฐ

 

๊ฐœ๋…์ ์œผ๋กœ for..in ๋ฃจํ”„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ๋ฒˆ ๋ฐ˜๋ณต๋˜๋Š” ๋‹จ์ผ ํ…Œ์ŠคํŠธ์™€ ์œ ์‚ฌ

 

 

 

for in ๋ฃจํ”„๋ณด๋‹ค ๋‚˜์€ ๋ฐฉ์‹

 

- ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋œ ํ…Œ์ŠคํŠธ๋Š” ๊ฐ ๊ฐœ๋ณ„ ์ธ์ˆ˜์˜ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ๊ฒฐ๊ณผ์—์„œ ๋ช…ํ™•ํ•˜๊ฒŒ ํ™•์ธ ๊ฐ€๋Šฅ

- ์„ธ๋ถ„ํšŒ๋œ ๋””๋ฒ„๊น…์„ ์œ„ํ•ด ์ธ์ˆ˜๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์žฌ์‹คํ–‰ ๊ฐ€๋Šฅ

- ์ธ์ˆ˜๋ฅผ ๋ณ‘๋ ฅ ์‹คํ–‰ํ•˜์—ฌ ๋” ํšจ์œจ์ ์œผ๋กœ ์‹คํ–‰ > ๊ฒฐ๊ณผ๋ฅผ ๋” ๋นจ๋ฆฌ ์–ป์Œ.

 

 


7๏ธโƒฃ  Swift Testing vs XCTest ๋น„๊ต

ํ•ญ๋ชฉ XCTest Swift Testing
ํ…Œ์ŠคํŠธ ์ธ์‹ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด test๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ @Test ์†์„ฑ ๋ช…์‹œ
์ง€์› ํƒ€์ž… ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ, ์ •์  ๋˜๋Š” ์ „์—ญํ•จ์ˆ˜
์–ด์„ค์…˜ ๋ฐฉ์‹ XCTAssert* ํ•จ์ˆ˜๋“ค #expect, #require ๋งคํฌ๋กœ
๋ณ‘๋ ฌ ์‹คํ–‰ ์ œํ•œ์  (ํ”„๋กœ์„ธ์Šค ๋‹จ์œ„) Swift ๋™์‹œ์„ฑ ๊ธฐ๋ฐ˜ ๋ณ‘๋ ฌ ์‹คํ–‰
์ƒํƒœ ๊ณต์œ  ๋ฐฉ์ง€ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜, ๊ณต์œ  ์œ„ํ—˜ ์กด์žฌ ๊ตฌ์กฐ์ฒด ๊ธฐ๋ฐ˜, ๊ฐ’ ํƒ€์ž… ๊ถŒ์žฅ
์ „ํ›„ ์ฒ˜๋ฆฌ setUp, tearDown ๋ฉ”์„œ๋“œ ( setUp() async throws) init, deinit ์‚ฌ์šฉ ( init() async throws )
๊ทธ๋ฃนํ™” ํด๋ž˜์Šค ์ƒ์† (XCTestCase์—์„œ ์ƒ์†) ์ค‘์ฒฉ ๊ตฌ์กฐ์ฒด ๋ฐ @Suite ์‚ฌ์šฉ (๊ตฌ์กฐ์ฒด, ์•กํ„ฐ, ํด๋ž˜์Šค ๊ฐ€๋Šฅ, ์˜๋„์น˜ ์•Š์€ ์ƒํƒœ๊ณต์œ ๋กœ ์ธํ•œ ๋ฒ„๊ทธ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์กฐ์ฒด ์ถ”์ฒœ )

 

 

 

- ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€๋Šฅ : ์ ์ง„์  ์ง„ํ–‰

- ๋‹จ์ผ ๋Œ€์ƒ์œผ๋กœ ์กด์žฌ ๊ฐ€๋Šฅ

- ์•ž์„œ ์„ค๋ช…ํ•œ๋Œ€๋กœ ๋งค๊ฐœํ™”๋œ ๋ณ€์ˆ˜ ํ…Œ์ŠคํŠธ ํ•˜๋‚˜๋กœ ํ†ตํ•ฉ

- ํ…Œ์ŠคํŠธ ์ด๋ฆ„์„ ์ •ํ•  ๋•Œ ๋”์ด์ƒ test ์•ˆ๋ถ™์—ฌ๋„ ๋จ.

 

 

- XCTest๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•ด์•ผ๋˜๋Š” ํ…Œ์ŠคํŠธ :

XCUIApplication ๊ณผ ๊ฐ™์€ UI ์ž๋™ํ™” API๋‚˜ XCTMetric๊ณผ ๊ฐ™์€ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” ์ง€์›๋˜์ง€ ์•Š์Œ. 

Objective-C๋กœ๋งŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ํ…Œ์ŠคํŠธ 

 - XCTest ์–ด์„ค์…˜ ํ•จ์ˆ˜๋ฅผ Swift Testing์—์„œ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ #expect ๋งคํฌ๋กœ๋ฅผ XCTest์—์„œ ํ˜ธ์ถœํ•˜์ง€ ๋ง๊ธฐ

 

 

 

๋ฌธ์„œ : Migrating a test from XCTest 

 -> ์–ด์„ค์…˜ ๋ณ€ํ™˜ํ•˜๊ณ  ๋น„๋™๊ธฐ ๋Œ€๊ธฐ ์กฐ๊ฑด ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ• ๋“ฑ 


8๏ธโƒฃ ์ปค๋งจ๋“œ๋ผ์ธ ๋ฐ ํ”Œ๋žซํผ ์ง€์›

  • swift test CLI์—์„œ ์‹คํ–‰ ์‹œ ์ฝ˜์†”์— ์ปฌ๋Ÿฌ ์ถœ๋ ฅ ํฌํ•จ ์ƒ์„ธ ๋กœ๊ทธ ์ œ๊ณต.
  • SwiftPM, Xcode 16, VSCode ๋“ฑ ์ฃผ์š” ๋„๊ตฌ์™€ ์—ฐ๋™๋จ.
  • Linux/Windows/macOS ๊ณตํ†ต ์ฝ”๋“œ๋ฒ ์ด์Šค ์‚ฌ์šฉ.
  • ๋ชจ๋“  ํ”Œ๋žซํผ์—์„œ ์ผ๊ด€์ ์œผ๋กœ ๋™์ž‘ 

command line ํ™˜๊ฒฝ
ํ„ฐ๋ฏธ๋„์—์„œ swift test ์ž…๋ ฅ ์‹œ ํŒจํ‚ค์ง€ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ


9๏ธโƒฃ ์˜คํ”ˆ ์†Œ์Šค ๋ฐ ์ปค๋ฎค๋‹ˆํ‹ฐ

  • GitHub์— ์˜คํ”ˆ ์†Œ์Šค๋กœ ๊ณต๊ฐœ๋จ.
  • Swift Forums์—์„œ ๊ธฐ๋Šฅ ์ œ์•ˆ, ํ† ๋ก , ํ”ผ๋“œ๋ฐฑ ๊ฐ€๋Šฅ.
  • ํ–ฅํ›„ swiftlang ์กฐ์ง์œผ๋กœ ์ด์ „ ์˜ˆ์ •.

โœ… ๊ฒฐ๋ก 

Swift Testing์€ Swift ์–ธ์–ด์˜ ์ฒ ํ•™๊ณผ ๋™์‹œ์„ฑ ๊ธฐ๋Šฅ์„ ๋ฐ˜์˜ํ•˜์—ฌ ํ…Œ์ŠคํŠธ์˜ ์ƒ์‚ฐ์„ฑ๊ณผ ์ •ํ™•์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ ์ค‘์‹ฌ์˜ ์˜คํ”ˆ์†Œ์Šค๋กœ ๋ฐœ์ „ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋ฉฐ, ๊ธฐ์กด XCTest์—์„œ ์ ์ง„์  ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๋„ ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•