iOS/WWDC

WWDC24) Swift testing์œผ๋กœ ํ…Œ์ŠคํŠธ ์‹ฌํ™”ํ•˜๊ธฐ

suvera 2025. 5. 25. 22:01
๋ฐ˜์‘ํ˜•

๐Ÿ“˜ Swift testing์œผ๋กœ ํ…Œ์ŠคํŠธ ์‹ฌํ™”ํ•˜๊ธฐ (Xcode 16 ๊ธฐ์ค€)

 

swift์˜ ๊ฐ•๋ ฅํ•˜๊ณ  ํ‘œํ˜„๋ ฅ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ์ตœ์‹  ์˜คํ”ˆ ์†Œ์Šค ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

- ํ…Œ์ŠคํŠธ๋Š” ๊ฐœ๋ฐœ ํ”„๋กœ์„ธ์Šค์˜ ์ค‘์š”ํ•œ ๋‹จ๊ณ„

- ์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋˜๊ธฐ ์ „์— ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ณ  ๋›ฐ์–ด๋‚œ ํ’ˆ์งˆ์˜ ์ œํ’ˆ์„ ์ถœ์‹œ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ž์‹ ๊ฐ

- ๊ณ„์† ๋Š˜์–ด๋‚˜๋Š” ํ…Œ์ŠคํŠธ ๋ชจ์Œ ๊ด€๋ฆฌ์˜ ์–ด๋ ค์›€

 

 

- ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ์ˆ˜๋ก ํ…Œ์ŠคํŠธ๋ฅผ ์ฝ๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋„๋ก ๋งŒ๋“œ๋Š”๊ฒŒ ์ค‘์š”

- ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์—์ง€ ์ผ€์ด์Šค๋ฅผ ๋‹ค๋ฃจ๋ ค๋ฉด ๋งŽ์€ ๋…ธ๋ ฅ ํ•„์š”

- ๋Œ€๊ทœ๋ชจ ํ…Œ์ŠคํŠธ ์ปฌ๋ ‰์…˜์„ ๊ตฌ์„ฑํ•˜๊ณ  ์—ฐ๊ด€์ง“๋Š” ๊ฒƒ์€ ๋ณต์žกํ•œ ์ผ์ด ๋  ์ˆ˜ ์žˆ์Œ

- ํ…Œ์ŠคํŠธ ์‚ฌ์ด์— ์ˆจ๊ฒจ์ง„ ์ข…์†์„ฑ > ํ…Œ์ŠคํŠธ ์ทจ์•ฝ, ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์˜ค๋ฅ˜ 

 

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

  • Swift Testing์€ Xcode 16์— ์ƒˆ๋กญ๊ฒŒ ๋„์ž…๋œ ๊ณต์‹ ์˜คํ”ˆ์†Œ์Šค ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ.
  • ๊ธฐ์กด XCTest์˜ ํ•œ๊ณ„๋ฅผ ๊ทน๋ณตํ•˜๊ณ , ํ‘œํ˜„๋ ฅ ์žˆ๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์šด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ง€์›. (Expressive code)
  • Swift ์–ธ์–ด ์ž์ฒด์˜ ํŠน์„ฑ๊ณผ ๋ฌธ๋ฒ•์„ ์ ๊ทน์ ์œผ๋กœ ํ™œ์šฉํ•จ.

 

2๏ธโƒฃ ๊ธฐ๋Œ€์น˜(Expectation) ์‹œ์Šคํ…œ : ์ฝ”๋“œ๊ฐ€ ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€

true/false์˜ ๊ฐ„๋‹จํ•œ ํ‘œํ˜„์‹

โœ… ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Œ€์น˜

  • expect(value == true) ๋˜๋Š” expect(user.name).toEqual("Suvera") ๋“ฑ์œผ๋กœ ์ฝ”๋“œ์˜ ์˜๋„๋ฅผ ๋ช…ํ™•ํžˆ ํ‘œํ˜„.
  • expect() ๋‚ด๋ถ€๋Š” ์ผ๋ฐ˜ Bool์ด ์•„๋‹ˆ๋ผ matcher ๊ธฐ๋ฐ˜ DSL๋กœ ๋™์ž‘ํ•จ.
 
 

โœ… ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ๊ธฐ๋Œ€์น˜ – expect throws

์˜ค๋ฅ˜์ฒ˜๋ฆฌ ํ…Œ์ŠคํŠธ๋Š” ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์— ์ค‘์š”. ์ž˜๋ชป๋œ ์ž…๋ ฅ๊ณผ ์˜ˆ์ƒ์น˜๋ชปํ•œ ์กฐ๊ฑด์„ ๋งˆ์ฃผ์นœ ๊ฒฝ์šฐ์—๋„ ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•˜๊ฒŒ ์‹คํŒจํ•˜๋„๋ก

 

- ์ฝ”๋“œ์˜ ํ•ดํ”ผ ํŒจ์Šค๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ณ  throw ํ•จ์ˆ˜๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐ˜ํ™˜๋˜๊ธฐ๋ฅผ ๊ธฐ๋Œ€ -> ํ…Œ์ŠคํŠธ ๋‚ด๋ถ€์—์„œ ํ˜ธ์ถœ

ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ํ…Œ์ŠคํŠธ ์‹คํŒจ

 

- ํ•จ์ˆ˜๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰๋˜๊ณ  ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ธฐ๋Œ€์น˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ์ƒ๊ณผ ๋งž๋Š”์ง€ ํ™•์ธ ๊ฐ€๋Šฅ 

 

- ๋ฐ˜๋ฉด, ์‹คํŒจ ์‚ฌ๋ก€๊ฐ€ ์˜๋„๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ํ•จ์ˆ˜๊ฐ€ ๋ฐœ์ƒ์‹œํ‚จ ์˜ค๋ฅ˜๋ฅผ catchํ•˜๊ณ  ๊ฒ€์‚ฌํ•ด์•ผ ํ•จ.

do-catch ๊ตฌ๋ฌธ ์ถ”๊ฐ€ ๋ฐฉ์‹ - ์ฝ”๋“œ๊ฐ€ ์žฅํ™ฉ, ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด ์ž˜ ์ง„ํ–‰๋๋Š”์ง€ ์•Œ์ˆ˜ ์—†์Œ

 

expect ๋งคํฌ๋กœ ์‚ฌ์šฉ : brew ํ•จ์ˆ˜๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฉด ์ด ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผ๋จ. ์˜ค๋ฅ˜๊ฐ€ ์—†์œผ๋ฉด ํ…Œ์ŠคํŠธ ์‹คํŒจ

 

 

  • ์˜ค๋ฅ˜๋ฅผ throwํ•  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€๋˜๋Š” ์ฝ”๋“œ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑ.
import Testing

@Test func brewTeaError() throws {
    let teaLeaves = TeaLeaves(name: "EarlGrey", optimalBrewTime: 4)
    #expect(throws: (any Error).self) {
        try teaLeaves.brew(forMinutes: 200) // We don't want this to fail the test!
    }
}
  • ํŠน์ • ์˜ค๋ฅ˜ ํƒ€์ž… ๊ฒ€์ฆ : ๋ชจ๋“  ์—๋Ÿฌ๋Œ€์‹  ํ•ด๋‹น ํƒ€์ž… ์ „๋‹ฌ
import Testing

@Test func brewTeaError() throws {
    let teaLeaves = TeaLeaves(name: "EarlGrey", optimalBrewTime: 4)
    #expect(throws: BrewingError.self) {
        try teaLeaves.brew(forMinutes: 200) // We don't want this to fail the test!
    }
}
  • ์ปค์Šคํ…€ ๊ฒ€์ฆ๋„ ๊ฐ€๋Šฅ: ์˜ค๋ฅ˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๋งž์ถคํ™”ํ•ด ํŠน์ • ํƒ€์ž…์ด๋‚˜ ์˜ค๋ฅ˜ ์‚ฌ๋ก€ ์—ฐ๊ฒฐ๋œ ๊ฐ’ ๋˜๋Š” ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ์—ฌ๋ถ€
  • ๋˜๋Š” ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜๊ฐ€ ์ž‘์—…์— ๋งž๋Š” ์˜ค๋ฅ˜์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋“ฑ 
import Testing

@Test func brewTeaError() throws {
    let teaLeaves = TeaLeaves(name: "EarlGrey", optimalBrewTime: 4)
    #expect(throws: BrewingError.oversteeped) {
        try teaLeaves.brew(forMinutes: 200) // We don't want this to fail the test!
    }
}
import Testing

@Test func brewTea() {
    let teaLeaves = TeaLeaves(name: "EarlGrey", optimalBrewTime: 4)
    #expect {
        try teaLeaves.brew(forMinutes: 3)
    } throws: { error in
        guard let error = error as? BrewingError,
              case let .needsMoreTime(optimalBrewTime) = error else {
            return false
        }
        return optimalBrewTime == 4
    }
}

 

 

3๏ธโƒฃ ํ•„์ˆ˜ ๊ธฐ๋Œ€์น˜ – require

  • ์˜ต์…”๋„ ๊ฐ’์ด nil์ด๋ฉด ์กฐ๊ธฐ์— ํ…Œ์ŠคํŠธ๋ฅผ ์ข…๋ฃŒ์‹œํ‚ด.
  • ์˜ˆ: guard let ๊ฐ™์€ ๋…ผ๋ฆฌ๋ฅผ require๋กœ ํ…Œ์ŠคํŠธ์— ์ ์šฉ ๊ฐ€๋Šฅ.
import Testing

@Test func brewAllGreenTeas() {
  #expect(throws: BrewingError.self) {
    brewMultipleTeas(teaLeaves: ["Sencha", "EarlGrey", "Jasmine"], time: 2)
  }
}

 

->  ๋ฐœ์ƒํ•˜๋Š” ๊ธฐ๋Œ€๊ฐ’์„ ํฌํ•จํ•œ ๋ชจ๋“  ์ผ๋ฐ˜ ๊ธฐ๋Œ€๊ฐ’์„ ํ•„์ˆ˜ ๊ธฐ๋Œ€๊ฐ’์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. 

import Testing

@Test func brewAllGreenTeas() throws {
  try #require(throws: BrewingError.self) {
    brewMultipleTeas(teaLeaves: ["Sencha", "EarlGrey", "Jasmine"], time: 2)
  }
}

 

 

- ์˜ต์…”๋„ ๊ฐ’์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒฝ์šฐ

 

-> ํ•„์ˆ˜ ๊ธฐ๋Œ€๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์ œ์–ด ํ๋ฆ„์„ ๋ฌธ์„œํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

-> ๋งˆ์ง€๋ง‰์— nil์ด ๋œ ๊ฐ’์„ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ์€ ์˜๋ฏธ๊ฐ€ ์—†์œผ๋ฏ€๋กœ  ํ•„์ˆ˜ ๊ธฐ๋Œ€๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ๋” ์ด์ƒ ํ• ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ ์กฐ๊ธฐ์— ์ข…๋ฃŒ

 

 

 

4๏ธโƒฃ ์‹คํŒจ๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ํ…Œ์ŠคํŠธ – withKnownIssue

  • ํ…Œ์ŠคํŠธ์—์„œ ์•Œ๋ ค์ง„ ์˜ค๋ฅ˜๋ฅผ ๋ฌธ์„œํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ. 
  • ํ…Œ์ŠคํŠธ ์‹คํŒจ ๋ถ„๋ฅ˜๋Š” ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ฆผ > ์ฆ‰์‹œ ์ˆ˜์ • ๋ถˆ๊ฐ€, ํ†ต์ œํ•  ์ˆ˜ ์—†๋Š” ์š”์ธ.. ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€๋˜์–ด ์‹ค์ œ ๋ฌธ์ œ๋ฅผ ์•Œ์•„์ฐจ๋ฆฌ์ง€ ๋ชปํ•จ.
  • ์™ธ๋ถ€ ์š”์ธ์œผ๋กœ ์ธํ•ด ์ผ์‹œ์ ์œผ๋กœ ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์˜ˆ์ƒ๋œ ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌ.
  • ์ด ์˜ค๋ฅ˜๋Š” ํ…Œ์ŠคํŠธ ๋ณด๊ณ ์„œ์—์„œ ‘์˜ˆ์ƒ๋œ ์‹คํŒจ(expected failure)’๋กœ ๊ธฐ๋ก๋จ → ์‹ค์ œ ๋ฒ„๊ทธ์™€ ๊ตฌ๋ถ„ ๊ฐ€๋Šฅ.
  • ์ด ๊ธฐ๋Šฅ์€ CI/CD์—์„œ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ํ”ผ๋“œ๋ฐฑ ๋ฃจํ”„๋ฅผ ์œ ์ง€ํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉ.

์•„์ด์Šคํฌ๋ฆผ ๊ธฐ๊ณ„๊ฐ€ ์•„์ด์Šคํฌ๋ฆผ ์ฝ˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ > ๊ธฐ๊ณ„๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š์•„ ์‹คํŒจ

 

ํ…Œ์ŠคํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•  ๊ฒฝ์šฐ .disabled๋ฅผ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ

 

 

withKnownIssue ์ถ”์ฒœ : ํ…Œ์ŠคํŠธ๊ฐ€ ๊ณ„์† ์‹คํ–‰๋˜๊ณ  ์ปดํŒŒ์ผ ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์•Œ๋ฆผ์„ ๋ฐ›์Œ

-> ํ•จ์ˆ˜๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์˜ˆ์ƒํ–ˆ๋˜ ์˜ค๋ฅ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๊ฐ€ ํ…Œ์ŠคํŠธ ์‹คํŒจ์— ํฌํ•จ๋˜์ง€ ์•Š์Œ !!

-> ๋Œ€์‹  ๊ฒฐ๊ณผ์—์„œ ์˜ˆ์ƒํ–ˆ๋˜ ์‹คํŒจ๋กœ ํ‘œ์‹œ๋จ.

-> ๋ฌธ์ œ ํ•ด๊ฒฐ ๋˜์–ด ๋” ์ด์ƒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด > ์•Œ๋ฆผ 

 

ํ•ด๋‹น ํ˜ธ์ถœ์„ ์ œ๊ฑฐํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ๋‹ค์‹œ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅ

 

 

- ํ…Œ์ŠคํŠธ์—์„œ ์—ฌ๋Ÿฌ ํ™•์ธ ์ˆ˜ํ–‰ 

์‹คํŒจํ•œ ๊ฒฝ์šฐ๋ฅผ withKnownIssue๋กœ ๋ž˜ํ•‘ > ๋‚˜๋จธ์ง€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Œ.

 

- Custom test descriptions : ํ…Œ์ŠคํŠธ ๋‚ด๋ถ€์—์„œ ์ผ์–ด๋‚˜๋Š” ์ผ์„ ํ•œ๋ˆˆ์— ํŒŒ์•… , ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์•ˆ๋‚ดํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์—ด๊ฑฐํ˜•์œผ๋กœ ์ž‘์—… > ๊ธฐ๋ณธ ์„ค๋ช…์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ„๋‹จ
๊ตฌ์กฐ์ฒด, ํด๋ž˜์Šค ๊ฐ™์ด ๋” ๋ณต์žกํ•œ ํƒ€์ž… > ๋” ๋งŽ์€ ๋…ธ์ด์ฆˆ ์ƒ์„ฑ, ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•ด๋‹น ํƒ€์ž…์˜ ์„ค๋ช…์— ํ…Œ์ŠคํŠธ ์ค‘์—๋Š” ์“ธ๋ชจ์—†๋Š” ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๊ธฐ ๋–„๋ฌธ'

 

์ •๋ณด ํ‘œ์‹œ > ํ•œ ๊ฐ’์„ ๋‹ค๋ฅธ ๊ฐ’๊ณผ ๊ตฌ๋ถ„ํ•˜๋Š” ๋ถ€๋ถ„์œผ ใ„น์ฐพ๊ธฐ ํž˜๋“ฌ. ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์œผ๋ฉด์„œ ๊ฐ๊ฐ์— ๊ฐ„๊ฒฐํ•œ ํ…Œ์ŠคํŠธ ์„ค๋ช…์„ ์ œ๊ณต

 

CustomTestStringConvertible ํ”„๋กœํ† ์ฝœ ์ฑ„ํƒ > ๋งž์ถคํ˜• ํ…Œ์ŠคํŠธ ์„ค๋ช… ์ œ๊ณต

 

ํ…Œ์ŠคํŠธ ๋ณด๊ณ ์„œ์˜ ๊ฐ€๋…์„ฑ ์ฆ๊ฐ€

 

5๏ธโƒฃ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋œ ํ…Œ์ŠคํŠธ – Parameterized Tests

- ์—์ง€ ์ผ€์ด์Šค๋ฅผ ํฌ์ฐฉํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์—์„œ ํ…Œ์ŠคํŠธ ์‹คํ–‰ํ•˜๋Š” ๊ฑด ์ข‹์ง€๋งŒ ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ฆผ

- ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๋ณ€์ˆ˜์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์œ ์ง€๊ด€๋ฆฌ ํž˜๋“ฌ > swift testing > ๋‹ค์–‘ํ•œ ์ธ์ˆ˜๋กœ ๋‹จ์ผ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ์‰ฝ๊ฒŒ ์‹คํ–‰

 

โœ… ๋ชฉ์ 

  • ๋ฐ˜๋ณต์ ์ธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋กœ ๋‹ค์–‘ํ•œ ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ.

์—ฌ๋Ÿฌ ๋ง›์˜ ์•„์ด์Šคํฌ๋ฆผ ์ค‘ ํŠน์ • ๋ง›์— ๊ฒฌ๊ณผ๋ฅ˜๊ฐ€ ํฌํ•จ๋๋Š”์ง€ ํ™•์ธ. containNuts ์†์„ฑ์€ ์—ด๊ฑฐ์˜ ๋ชจ๋“  ์ผ€์ด์Šค์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ ํ•„์š”.
๋ฐ”๋‹๋ผ ๋‹จ์ผ

 

 

 

๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋œ ํ…Œ์ŠคํŠธ

 

- ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋Š” ์„œ๋กœ ์™„์ „ํžˆ ๋…๋ฆฝ์ , ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅ 

- ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์‹œ๊ฐ„์ด for๋ฃจํ”„๋‚˜ ๋ณ„๋„์˜ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋ณด๋‹ค ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.

 

 

 

- xcode๋Š” ์ž…๋ ฅ ์œ ํ˜•์ด Codable์„ ์ฑ„ํƒํ•˜๋Š” ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์˜ ๊ฐœ๋ณ„ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์žฌ์‹คํ–‰์„ ์ง€์›.

- ์ด๋ฅผ ํ†ตํ•ด ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰๋œ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•  ํ•„์š”์—†์ด ์‹คํŒจํ•œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋งŒ์„ ์žฌ์‹œ๋„

 

โœ… ๋‹จ์ผ ์ธ์ˆ˜ ์˜ˆ์‹œ

  • ๊ฐ ์ธ์ˆ˜๋Š” ํ…Œ์ŠคํŠธ ๋‚ด๋น„๊ฒŒ์ดํ„ฐ์—์„œ ๋ณ„๋„์˜ ์‹คํ–‰ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌ, ๋ณ‘๋ ฌ ์‹คํ–‰ ๊ฐ€๋Šฅ.

 

์ด ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๊ฐ€ ๋ฐฐ์—ด์˜ ๊ฐ’ ์ค‘ ํ•˜๋‚˜์— ๋Œ€ํ•ด ์‹คํŒจํ•˜๋ฉด ์‹คํ–‰์ด ์ค‘๋‹จ๋˜๊ณ  ํ›„์† ์ธ์ˆ˜๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜์ง€ ์•Š์Œ. ์–ด๋–ค ๊ฐ’์ด ์‹คํŒจ ํ–ˆ๋Š”์ง€ ๋ถˆ๋ถ„๋ช…
์ž…๋ ฅ์„ ์œ„๋กœ ์ด๋™ ์‹œ์ผœ ํ…Œ์ŠคํŠธ ์†์„ฑ์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Œ. ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋ฅผ ์œ„ํ•ด ์ปฌ๋ ‰์…˜์„ test ์†์„ฑ์œผ๋กœ ์ „๋‹ฌํ•˜๋ฉด, ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ปฌ๋ ‰์…˜์˜ ๊ฐ ์š”์†Œ๋ฅผ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์— ์ „๋‹ฌ

 

ํ•˜๋‚˜๊ฐ€ ์‹คํŒจํ•˜๋ฉด ์–ด๋–ค ์ž…๋ ฅ์— ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•œ์ง€ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œ์‹œ

 

๋‘๋ฒˆ์งธ ํ•จ์ˆ˜ ์ถ”๊ฐ€

 

์—ด๊ฑฐํ˜• ์™ธ์—๋„ ๋ชจ๋“  sendable ์ปฌ๋ ‰์…˜์„ ํ…Œ์ŠคํŠธ ์†์„ฑ์— ์ „๋‹ฌ ๊ฐ€๋Šฅ

 

 

โœ… ๋‹ค์ค‘ ์ธ์ˆ˜ ์˜ˆ์‹œ

  • zip์„ ํ™œ์šฉํ•ด ๋ชจ๋“  ์กฐํ•ฉ์ด ์•„๋‹ˆ๋ผ 1:1 ๋งคํ•‘๋งŒ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Œ.

์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜ ๋’ค์— ๋‹ค๋ฅธ ์ธ์ˆ˜ ์ถ”๊ฐ€ , ๋‘๋ฒˆ์งธ ์ปฌ๋ ‰์…˜์˜ ๋ชจ๋“  ์š”์†Œ๋Š” ๋‘๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ, ์ด ๋‘ ์ปฌ๋ ‰์…˜์˜ ๋ชจ๋“  ์š”์†Œ ์กฐํ•ฉ์ด ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŠธ ๋จ.

 

์ธ์ˆ˜๊ฐ€ ๋‘๊ฐœ์ธ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋Š” ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์กฐํ•ฉ์„ ํ…Œ์ŠคํŠธ ํ•จ

 

๋” ๋งŽ์€ ์ž…๋ ฅ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์˜ ์ˆ˜๋Š” ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ์ฆ๊ฐ€

 

=> ์ด๋Ÿฌํ•œ ์ฆ๊ฐ€๋ฅผ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธํ•จ์ˆ˜๋Š” ์ตœ๋Œ€ ๋‘๊ฐœ์˜ ์ปฌ๋ ‰์…˜์„ ํ—ˆ์šฉ 

=> Swift ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ zip ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ์ž…๋ ฅ ์Œ์„ ์ง์ง€์„ ์ˆ˜๋„ ์žˆ๋‹ค

 

zip ์„ ํ˜ธ์ถœํ•˜๋ฉด ์Œ์œผ๋กœ ์—ฐ๊ฒฐ๋จ.

 

- zip์€ ํŠœํ”Œ์˜ ์‹œํ€€์Šค๋ฅผ ์ƒ์„ฑ

 

1๋ฒˆ์งธ ์ปฌ๋ ‰์…˜์˜ ๊ฐ ์š”์†Œ๋ฅผ ๋‘๋ฒˆ์งธ ์ปฌ๋ ‰์…˜์˜ ์š”์†Œ์™€ ์ˆœ์„œ๋Œ€๋กœ ์Œ์œผ๋กœ ๋ฌถ๋Š” ๋ฐฉ์‹

 

 


6๏ธโƒฃ ํ…Œ์ŠคํŠธ ์ •๋ฆฌ ์ „๋žต: ๋ชจ์Œ๊ณผ ํƒœ๊ทธ

โœ… ํ…Œ์ŠคํŠธ ๋ชจ์Œ(Collection)

  • ํ…Œ์ŠคํŠธ๋ฅผ ๋…ผ๋ฆฌ์  ๊ทธ๋ฃน์œผ๋กœ ๊ตฌ์กฐํ™”ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ.
  • ํ•˜์œ„ ๋ชจ์Œ์„ ํฌํ•จํ•ด ํŠธ๋ฆฌ ๊ตฌ์กฐ ํ˜•์„ฑ ๊ฐ€๋Šฅ.

suite์— ๋‹ค๋ฅธ suite ํฌํ•จ ๊ฐ€๋Šฅ : ํ…Œ์ŠคํŠธ๋ฅผ ๋”์šฑ ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Œ

 

 

- ๋”ฐ๋“ฏํ•œ ๋””์ €ํŠธ, ์ฐฌ ๋””์ €ํŠธ 

- add sub suites -> ํ…Œ์ŠคํŠธ ๊ทธ๋ฃน ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

โœ… ํƒœ๊ทธ(Tag)

  • ํŒŒ์ผ/๋ชจ์Œ์— ๊ด€๊ณ„์—†์ด ํ…Œ์ŠคํŠธ ๊ฐ„ ๋…ผ๋ฆฌ์  ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ๋„๊ตฌ.
  • ์˜ˆ: caffeinated, chocolatey, spicy, experimental
  • ํƒœ๊ทธ ๊ธฐ๋ฐ˜์œผ๋กœ ํ…Œ์ŠคํŠธ ์‹คํ–‰, ํ•„ํ„ฐ๋ง, ๊ทธ๋ฃนํ™”, ํ…Œ์ŠคํŠธ ๊ณ„ํš ๊ตฌ์„ฑ ๊ฐ€๋Šฅ

 

  • ๋ณต์žกํ•œ ํŒจํ‚ค์ง€๋‚˜ ํ”„๋กœ์ ํŠธ์—๋Š” ์ˆ˜๋ฐฑ ~ ์ˆ˜์ฒœ๊ฐœ์˜ ํ…Œ์ŠคํŠธ์™€ ๋ชจ์Œ์ด ํฌํ•จ ๋  ์ˆ˜ ์žˆ์Œ
  • ์ผ๋ถ€ ํ…Œ์ŠคํŠธ์˜ ํ•˜์œ„ ์„ธํŠธ๋Š” ๊ณตํ†ต๋œ ํŠน์„ฑ์„ ๊ณต์œ  ํ•  ์ˆ˜ ์žˆ์Œ

์ผ๋ถ€ ํ…Œ์ŠคํŠธ๋Š” ์นดํŽ˜์ธ์ด ํ•จ์œ ๋œ ์Œ์‹๊ณผ ๊ด€๋ จ, ์ผ๋ถ€๋Š” ์ดˆ์ฝœ๋ฆฟ์ด ๋“  ์Œ์‹๊ณผ ๊ด€๋ จ -> ์ด ๊ฒฝ์šฐ ํƒœ๊ทธ๋กœ ๋‘ ์„ธํŠธ์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์—ฐ๊ฒฐ

- ์œ ์˜ํ•  ์  : ํƒœ๊ทธ๋Š” ํ…Œ์ŠคํŠธ ๋ชจ์Œ์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์—†๋‹ค. 

- ๋ชจ์Œ์€ ์†Œ์Šค ์ˆ˜์ค€์—์„œ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์— ๊ตฌ์กฐ๋ฅผ ๋ถ€์—ฌํ•˜์ง€๋งŒ ํƒœ๊ทธ๋Š” ๊ณตํ†ต์ ์„ ๊ณต์œ ํ•˜๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ํŒŒ์ผ, ๋ชจ์Œ, ๋Œ€์ƒ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ. 

 

 

ํƒœ๊ทธ ์„ ์–ธ ๋ฐฉ๋ฒ• 

 

- ๋ชจ๋“  ์Œ๋ฃŒ์— ์นดํŽ˜์ธ์ด ๋“ค์–ด์žˆ๊ณ , ์—์Šคํ”„๋ ˆ์†Œ ๋ธŒ๋ผ์šฐ๋‹ˆ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€

-> caffeinated ํƒœ๊ทธ๋ฅผ ๋งŒ๋“ค์–ด ํ…Œ์ŠคํŠธ๊ฐ€ ๋ณ„๋„์˜ ๋ชจ์Œ์— ์กด์žฌํ•ด๋„ ์„œ๋กœ ์—ฐ๊ด€์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ

 

extension์— ์ •์  ๋ณ€์ˆ˜ ์„ ์–ธ, ๋ณ€์ˆ˜๋Š” tag์˜ ์ธ์Šคํ„ด์Šค์—ฌ์•ผ ํ•จ

 

- ๋น„๋ฐ€ ์žฌ๋ฃŒ -> tag ์†์„ฑ์„ ๋ณ€์ˆ˜์— ์ถ”๊ฐ€ํ•ด ํ…Œ์ŠคํŠธ์—์„œ ํƒœ๊ทธ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก 

 

ํƒœ๊ทธ๋Š” drinkTests์˜ ๋ชจ์Œ ์ˆ˜์ค€์—์„œ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Œ. ์ด ํ…Œ์ŠคํŠธ์— ์‚ฌ์šฉ๋œ ๋ชจ๋“  ์Œ๋ฃŒ๋Š” ์นดํŽ˜์ธ์ด ๋“ค์–ด์žˆ๊ณ  ํ…Œ์ŠคํŠผ๋А ํ•ด๋‹น ๋ชจ์Œ์—์„œ ํƒœ๊ทธ๋ฅผ ์ƒ์†. -> expressoBrownieTexture์— ์ถ”๊ฐ€ , DessertTests์— ์žˆ๋Š” ์œ ์ผํ•œ ์นดํŽ˜์ธ์ด ๋“  ์‹ํ’ˆ์ด๋ฏ€๋กœ ์ „์ฒด DessertTests ๋ชจ์Œ์— ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ๊ฒƒ.

 

- ํƒœ๊ทธ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. 

- ๋ชจ์นด์™€ ์—์Šคํ”„๋ ˆ์†Œ ๋ธŒ๋ผ์šฐ๋‹ˆ๋Š” ๋ชจ๋‘ ์นดํŽ˜์ธ์ด ์žˆ์ง€๋งŒ ์žฌ๋ฃŒ๊ฐ€ ์ดˆ์ฝœ๋ฆฟ์ž„

 

-> ํ…Œ์ŠคํŠธ ๋‚ด๋น„๊ฒŒ์ดํ„ฐ๊ฐ€ ํ…Œ์ŠคํŠธ๋ฅผ ํƒœ๊ทธ๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ํŠน์ • ํƒœ๊ทธ๊ฐ€ ์žˆ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ

 

 

- ๋‚ด๋น„๊ฒŒ์ดํ„ฐ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์†Œ์Šค ์ฝ”๋“œ์—์„œ ํ•ด๋‹น ์œ„์น˜์— ๋”ฐ๋ผ ์ •๋ฆฌ๋œ ํ…Œ์ŠคํŠธ๋ฅผ ํ‘œ์‹œ

- ํ…Œ์ŠคํŠธ ๋‚ด๋น„๊ฒŒ์ดํ„ฐ ํ•˜๋‹จ์˜ ํ•„ํ„ฐ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ํ•ซ์†Œ์Šค ๊ด€๋ จ ํ…Œ์ŠคํŠธ ์ฐพ๊ธฐ

 

- xcode์˜ ํƒœ๊ทธ ์ œ์•ˆ

- seasonal, spicy, street food์™€ ๊ฐ™์€ ํƒœ๊ทธ ์ œ์•ˆ ํ‘œ์‹œ 

 

- ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•„ํ„ฐ ํ•„๋“œ๋Š” ํ…Œ์ŠคํŠธ์˜ ํ‘œ์‹œ, ํ•จ์ˆ˜ ์ด๋ฆ„๊ณผ ์ผ์น˜

- ์ง„์ €๋ธŒ๋ ˆ๋“œ ์ฟ ํ‚ค์˜ ์ŠคํŒŒ์ด์Šค ์กฐํ•ฉ๊ณผ ์‹œ๊ธˆ์น˜์™€ ์•„ํ‹ฐ์ดˆํฌ ๋”ฅ์†Œ์Šค ๋น„์œจ ๋“ฑ์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ํ‘œ์‹œ 

 

 

- ์ด๋ฆ„์— ๊ฐ•์กฐ ํ‘œ์‹œ๋œ ๋‹จ์–ด๊ฐ€ ์—†๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ œ์•ˆ -> ์ผ์น˜ํ•˜๋Š” ํƒœ๊ทธ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ

- ์ œ์•ˆ ํŒ์—…์—์„œ spicy ํด๋ฆญ > ์ž…๋ ฅํ•œ ๋‚ด์šฉ์„ ํ…Œ์ŠคํŠธ ๋‚ด๋น„๊ฒŒ์ดํ„ฐ๊ฐ€ ํƒœ๊ทธ ํ•„ํ„ฐ๋กœ ๋ณ€ํ™˜ > ํ•ด๋‹น ํƒœ๊ทธ๊ฐ€ ์—†๋Š” ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ์ œ๊ฑฐ

 

 

๊ทธ๋ฃนํ™”๋œ ํƒœ๊ทธ๋“ค

 

 

 

 

7๏ธโƒฃ ํ…Œ์ŠคํŠธ ๊ณ„ํš(Test Plan)

  • ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ํ•ต์‹ฌ ํ…Œ์ŠคํŠธ ์„ธํŠธ๊ฐ€ ์žˆ๋Š” ํ…Œ์ŠคํŠธ ๊ณ„ํš ๋งŒ๋“ค๊ธฐ ๊ฐ€๋Šฅ
  • ๋ณ€๊ฒฝ ์‹œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ„๊ทธ๋ฅผ ๋น ๋ฅด๊ฒŒ ํฌ์ฐฉ

  • Include Tags, Exclude Tags ๊ธฐ๋Šฅ ์ œ๊ณต.
  • ์˜ˆ: @seasonal, @unreleased ํƒœ๊ทธ๋ฅผ ์ œ์™ธํ•œ ํ•ต์‹ฌ ํ…Œ์ŠคํŠธ๋งŒ ์‹คํ–‰.
  • Xcode ๋‚ด์—์„œ ํƒœ๊ทธ๋ณ„ ์‹คํ–‰ ๋ฐ ๋ณด๊ณ ์„œ ๋ถ„์„ ๊ฐ€๋Šฅ.
  • UI์—์„œ ํƒœ๊ทธ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ ์‹คํ–‰ → ํŠน์ • ๊ธฐ๋Šฅ์ด๋‚˜ ์‹œ๊ธฐ๋ณ„ ํ…Œ์ŠคํŠธ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ.

๋‹จ์œ„ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ํ™•์žฅ > ๋ชจ๋“  ํ…Œ์ŠคํŠธ ํ™•์ธ

 

- ํ…Œ์ŠคํŠธ ๊ณ„ํš ์—…๋ฐ์ดํŠธ : ๋ชจ๋“  ํ•ต์‹ฌ ํ…Œ์ŠคํŠธ ์‹คํ–‰, sesonal ํƒœ๊ทธ๊ฐ€ ์ž‡๋Š” ํ…Œ์ŠคํŠธ ์ œ์™ธ 

 

๋‘๊ฐœ ์ด์ƒ์˜ ํƒœ๊ทธ

 

- ํ…Œ์ŠคํŠธ ๋ณด๊ณ ์„œ

์ธ์‚ฌ์ดํŠธ ํ™”๋ฉด ใ…ฃ ํ…Œ์ŠคํŠธ ์‹คํŒจ์˜ ํŒจํ„ด์„ ๋ณด์—ฌ์ฃผ๋Š” ์„น์…˜

 

- spicy ํƒœ๊ทธ ๊ด€๋ จ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจ 

 

xcode cloud๋„ swift testing์„ ์ง€์›ํ•˜๋„๋ก ์—…๋ฐ์ดํŠธ ๋จ

 

app store connect > xcode cloud ํƒญ์—์„œ ๋ณผ์ˆ˜ ์žˆ์Œ

 

 

 

 

 

8๏ธโƒฃ ๋ณ‘๋ ฌ ์‹คํ–‰ & ์ง๋ ฌํ™” ์ œ์–ด

โœ… ๋ณ‘๋ ฌ ํ…Œ์ŠคํŠธ

  • Swift Testing์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณ‘๋ ฌ ์‹คํ–‰์„ ์ง€์›. 
  • ๋ชจ๋“  ๋ฌผ๋ฆฌ์  ๊ธฐ๊ธฐ์—์„œ ๋ณ‘๋ ฌ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํ•  ์ˆ˜ ์žˆ์Œ
  • ๋™๊ธฐ/๋น„๋™๊ธฐ ์—ฌ๋ถ€ ๊ด€๊ณ„์—†์ด ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌ๋จ.
  • ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋žœ๋คํ™”(shuffled) ํ•˜์—ฌ ํ…Œ์ŠคํŠธ ๊ฐ„ ์ˆจ๊ฒจ์ง„ ์˜์กด์„ฑ ๊ฐ์ง€ ๊ฐ€๋Šฅ.

 

์žฅ์  > ์‹คํ–‰ ์‹œ๊ฐ„ ๋‹จ์ถ•

 

- XCTest์™€ ํฐ ์ฐจ์ด์  : ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ณ‘๋ ฌํ™”๋งŒ ์ง€์›ํ•˜์—ฌ, ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ๋งŒ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ๋Š” ๋‹ค๋ฆ„

- ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋ฅผ MainActor๊ฐ™์€ ๊ธ€๋กœ๋ฒŒ ์•กํ„ฐ์— ๊ฒฉ๋ฆฌ ๊ฐ€๋Šฅ

์‹คํ–‰ ์ˆœ์„œ ๋žœ๋คํ™”

 

์ด ํ…Œ์ŠคํŠธ๊ฐ€ ํ•ญ์ƒ ์ˆœ์„œ๋Œ€๋กœ ์ฐจ๋ก€๋ฅผ ์ง€์ผœ ์‹คํ–‰๋˜๋ฉด ๋‘๋ฒˆ์งธ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์ปต์ผ€์ดํฌ๊ฐ€ ๋Š˜ ์ค€๋น„๋˜์–ด ์žˆ์Œ
ํ…Œ์ŠคํŠธ๊ฐ€ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰๋˜๋ฉด ์ฒซ๋ฒˆ์งธ์— ๋Œ€ํ•œ ๋‘ ๋ฒˆ์งธ์˜ ์ข…์†์„ฑ์ด ๋Ÿฐํƒ€์ž„์— ๋…ธ์ถœ๋˜์–ด ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Œ

 

- ์ด์ „ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ, ์ด๋Ÿฌํ•œ ์ข…์†์„ฑ ์ค‘ ์ผ๋ถ€๊ฐ€ ์ด๋ฏธ ๋ฒ ์ดํฌ ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. 

- ์Šค์œ„ํ”„ํŠธ 6์€ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•  ๋•Œ ์ผ๋ถ€ ๋ฌธ์ œ ๋ฐœ๊ฒฌ์— ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ๋ฌธ์ œ๋Š” ์ฐพ๊ธฐ ํž˜๋“ฌ

- ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„๋กœ ์ฝ”๋“œ๋ฅผ swift testing์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๋ฌธ์ œ๋Š” ๋‚˜์ค‘์— ํ•ด๊ฒฐํ•˜๊ณ  ์‹ถ์„์ˆ˜๋„ 

 

 

โœ… ์ง๋ ฌ ์‹คํ–‰ ์ œ์–ด

 
  • @serialized ๋ชจ์Œ ๋˜๋Š” ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์— ์ ์šฉ → ํ…Œ์ŠคํŠธ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰.
  • ํ•˜์œ„ ๋ชจ์Œ์—๋„ ์ ์šฉ๋จ (์ž๋™ ์ƒ์†๋จ).

ํ…Œ์ŠคํŠธ๋ฅผ ์ง๋ ฌ๋กœ ์‹คํ–‰ํ•ด์•ผ๋จ.

 

-> ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๋จผ์ € ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๋„๋ก ๋ฆฌํŒฉํ† ๋ง ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ ค !

- .serialized๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋œ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์— ์ ์šฉ๋˜์–ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ์‹คํ–‰๋˜๋„๋ก ํ•  ์ˆ˜๋„ ์žˆ์Œ

 

์ง๋ ฌ๋กœ ์‹คํ–‰

 

- ๊ทธ๋Ÿฌ๋‚˜ ์Šค์œ„ํ”„ํŠธ๋Š” ์ด๋Ÿฐ ์ง๋ ฌํ™”๋œ ํ…Œ์ŠคํŠธ์™€ ๊ด€๋ จ ์—†๋Š” ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ๋Š” ๋ณ‘๋ ฌ์œผ๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅ

 

- ๋ณ‘๋ ฌ ํ…Œ์ŠคํŠธ ๊ธฐ๋ณธ : ๋น ๋ฅด๊ฒŒ ์‹คํ–‰ 

- ๋ณ‘๋ ฌ๋กœ ๋ฆฌํŒฉํ† ๋ง ๊ณ ๋ ค 

 

9๏ธโƒฃ ๋น„๋™๊ธฐ ํ…Œ์ŠคํŠธ์™€ ์ฝœ๋ฐฑ

 

๋™์‹œ ์‹คํ–‰ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ swift์—์„œ๋„ ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์—์„œ์™€ ๊ฐ™์ด ๋™์ผํ•œ ๋™์‹œ ์‹คํ–‰ ๊ธฐ๋Šฅ ์‚ฌ์šฉ

โœ… async/await ์ง€์›

  • Swift์˜ async/await ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.
  • Swift Testing์€ Task ๋‚ด๋ถ€์—์„œ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ž‘๋™ํ•จ.
  • ์ž‘์—…์ด ์ข…๋ฃŒ๋˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ cpu๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ…Œ์ŠคํŠธ๋ฅผ ์ผ์‹œ ์ค‘๋‹จ

โœ… ์™„๋ฃŒ ํ•ธ๋“ค๋Ÿฌ → continuation ๋ณ€ํ™˜

  • completionHandler ๊ธฐ๋ฐ˜ ์ฝ”๋“œ๋„ async๋กœ ์‰ฝ๊ฒŒ ๋ž˜ํ•‘ ๊ฐ€๋Šฅ.
  • c, obj-c: ์™„๋ฃŒ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๋์„ ์•Œ๋ฆผ 

ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋œ ํ›„ ์‹คํ–‰๋˜๋ฏ€๋กœ ํ•จ์ˆ˜๊ฐ€ ์„ฑ๊ณตํ–‡๋Š”์ง€ ํ™•์ธ ใ…‚๋ฃจ๊ฐ€
์Šค์œ„ํ”„ํŠธ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์™„๋ฃŒ ํ•ธ๋“ค๋Ÿฌ์— ๋Œ€ํ•ด ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋น„๋™๊ธฐ ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ œ๊ณต
ํ…Œ์ŠคํŠธ ์ค‘์ธ ์ฝ”๋“œ๊ฐ€ ์™„๋ฃŒ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๋น„๋™๊ธฐ ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋ฉด -> withCheckedContinuation ๋˜๋Š” withCheckedThrowingContinuation์œผ๋กœ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋Š” ํ‘œํ˜„์‹์œผ๋กœ ๋ณ€ํ™˜

โœ… ์ด๋ฒคํŠธ ํ™•์ธ – confirmation

  • ์ด๋ฒคํŠธ๊ฐ€ ๋ช‡ ๋ฒˆ ํ˜ธ์ถœ๋˜๋Š”์ง€ ํ™•์ธ ๊ฐ€๋Šฅ (confirmation(count:))
  • ๊ธฐ๋ณธ๊ฐ’์€ 1ํšŒ, 0 ์„ค์ • ์‹œ ํ˜ธ์ถœ๋˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ์ƒํ™ฉ ๊ฒ€์ฆ ๊ฐ€๋Šฅ.

๋˜ ๋‹ค๋ฅธ ์ฝœ๋ฐฑ์€ ๋‘๋ฒˆ ์ด์ƒ ์‹คํ–‰ ๋  ์ˆ˜ ์žˆ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ

- ์ „์ฒด ์‹์‹œ๊ฐ€ ใ„ท๋๋‚ ๋•Œ๋งˆ๋‹ค ์ฝœ๋ฐฑ ํ˜ธ์ถœ์ด ์•„๋‹ˆ๋ผ ๊ฐ ์ฟ ํ‚ค๋งˆ๋‹ค ํ•œ๋ฒˆ ์”ฉ ํ˜ธ์ถœ

- ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ๋จน์€ ์ฟ ํ‚ค์˜ ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๋ ค๊ณ  ํ•˜๋ฉด  ์Šค์œ„ํ”„ํŠธ 6์˜ ๋™์‹œ ์‹คํ–‰ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ 

- ์ด๋ ‡๊ฒŒ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๋Š”๊ฒŒ ์•ˆ์ „ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— 

 

- ํ…Œ์ŠคํŠธ ์ค‘์ธ ์ฝ”๋“œ๊ฐ€ ์ฝœ๋ฐฑ์„ ๋‘ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ณ , ํ˜ธ์ถœ ํšŸ์ˆ˜๋ฅผ ํ…Œ์ŠคํŠธํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ confirmation ์‚ฌ์šฉ.

- ๋‹ค๋ฅธ ์—์ƒ ํšŸ์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

 

 

๐Ÿ”Ÿ ํ…Œ์ŠคํŠธ ์ธ์‚ฌ์ดํŠธ ๋ฐ ํƒœ๊ทธ ๊ธฐ๋ฐ˜ ๋ถ„์„

  • ํ…Œ์ŠคํŠธ ๋ฆฌํฌํŠธ์— ํƒœ๊ทธ ์ •๋ณด๊ฐ€ ํ•จ๊ป˜ ํ‘œ์‹œ๋จ.
  • ์‹คํŒจ ํŒจํ„ด → ๊ณตํ†ต ํƒœ๊ทธ ๊ธฐ๋ฐ˜ ๋ถ„์„ ๊ฐ€๋Šฅ (spicy ํƒœ๊ทธ ํ…Œ์ŠคํŠธ๊ฐ€ ์ „๋ถ€ ์‹คํŒจํ•จ ๋“ฑ).
  • UI์ƒ์—์„œ ํƒœ๊ทธ๋ณ„ ์‹คํ–‰ ๋ฒ„ํŠผ ๋ฐ ์‹คํŒจ ํ•„ํ„ฐ ์ œ๊ณต → ๋น ๋ฅธ ๋””๋ฒ„๊น… ๊ฐ€๋Šฅ.

๐Ÿง  Swift Testing์˜ ์žฅ์  ์š”์•ฝ


  XCTest Swift Testing
ํ‘œํ˜„๋ ฅ ์ œํ•œ์  ํ’๋ถ€ํ•œ DSL ๊ธฐ๋ฐ˜
์˜ค๋ฅ˜ ํ…Œ์ŠคํŠธ ๋ณต์žกํ•จ (do-catch) expect throws ํ•œ ์ค„ ์ฒ˜๋ฆฌ
๋งค๊ฐœ๋ณ€์ˆ˜ ํ…Œ์ŠคํŠธ ์—†์Œ @Test(arguments:) ์ง€์›
ํƒœ๊ทธ/๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ถˆ๊ฐ€๋Šฅ ํƒœ๊ทธ ๋ฐ ์ •๋ฆฌ ๊ฐ€๋Šฅ
๋ณ‘๋ ฌ ์‹คํ–‰ ์ œํ•œ์  ๊ธฐ๋ณธ ๋ณ‘๋ ฌ, ์ง๋ ฌํ™” ์ œ์–ด ๊ฐ€๋Šฅ
๋น„๋™๊ธฐ ์ง€์› ์ง€์› await ๋ฐ continuation ์™„์ „ ํ†ตํ•ฉ
์œ ์ง€๋ณด์ˆ˜ ๋ถˆํŽธํ•จ ๊ตฌ์กฐํ™”๋œ ๊ด€๋ฆฌ ์ „๋žต
 

๐Ÿ“Œ ๊ฒฐ๋ก 

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

๋ฐ˜์‘ํ˜•