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

Unit Test ์˜ˆ์‹œ

  1. URLRequest ์ค€๋น„
  2. Task ์ƒ์„ฑ
  3. ์„œ๋ฒ„์™€ ํ†ต์‹ 
  4. Response parsing
  5. View Update

์ผ๋ฐ˜์ ์ธ ์ด๋Ÿฌํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ Unit test๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“ˆ์€ request๋ฅผ ์ค€๋น„ํ•˜๋Š” ๊ณผ์ •, ๊ทธ๋ฆฌ๊ณ  response๋ฅผ ํŒŒ์‹ฑํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.

Integration Test์˜ ๊ฒฝ์šฐ, ์ผ๋ จ์˜ ๊ณผ์ •์„ ํ•œ๊บผ๋ฒˆ์— ํ™•์ธํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ End-to-End Test(UI Test)๋Š” ์‹ค์ œ UI๊นŒ์ง€ ์ „์ฒด์ ์œผ๋กœ ๋ณด๋Š” ๊ฒƒ์„ ๋ง—ํ•œ๋‹ค.

์™œ ํ•„์š”ํ• ๊นŒ?

์‚ฌ๋žŒ์€ ์‹ค์ˆ˜ํ•˜๋‹ˆ๊นŒ

  • ์‚ฌ๋žŒ์˜ ์‹ค์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ๋“ค
    • Swift Compiler: Language Type์„ ์œ„ํ•ด
    • SwiftLint: Validation์„ ์œ„ํ•ด
    • Code Review: code quality๋ฅผ ์œ„ํ•ด
    • Test: ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์œ„ํ•ด
  • ์ž๋™ํ™”๋œ Test์˜ ๊ฐ•์ 
    • ์†Œ์Šค์ฝ”๋“œ์˜ ๊ธฐ๋ณธ ๋™์ž‘ ๊ฒ€์ฆ
    • ๋ฆฌํŒฉํ† ๋ง์— ์œ ๋ฆฌ
    • Usecase๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ (Documentation ๋Œ€์ฒด)
    • Interface ์„ค๊ณ„๋ฅผ ๊ฐ•์š”ํ•จ
      • Testability ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด ์„ค๊ณ„๋ฅผ ๊ณ ๋ฏผํ•ด์•ผ ํ•จ
  • ํ•˜์ง€๋งŒ 100% ๋ฒ„๊ทธ ์—†๋Š” ์ฝ”๋“œ๋ฅผ ๋ณด์žฅํ•ด์ฃผ์ง€๋Š” ์•Š๋Š”๋‹ค. ๋ณด์™„ํ•  ๋ฟ.

XCTestCase

  • ํ•˜๋‚˜์˜ Test Target์— XCTestCase๋ฅผ ์ƒ์†๋ฐ›์€ ์—ฌ๋Ÿฌ๊ฐœ์˜ Test Class๊ฐ€ ์กด์žฌํ•œ๋‹ค.
  • Test Class ๋ณ„ ์—ฌ๋Ÿฌ Test Case method๊ฐ€ ์žˆ๋‹ค.

์ฒ˜์Œ Target์„ ๋งŒ๋“ค๊ณ  ์ ์šฉํ•˜๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค๊ฐ€ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์ง„๋‹ค.

import XCTest
@testable import ExampleApp
 
class ExampleAppTests: XCTestCase {
    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }
 
    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }
 
    func testExample() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }
 
    func testPerformanceExample() throws {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }
}
  • setUpWithError(), tearDownWithError(): ๊ฐ test case์‹คํ–‰ ์ „ ํ›„ ๊ฐ๊ฐ ์‹คํ–‰๋œ๋‹ค.
    • setUpWithError() โ†’ testA() โ†’ tearDownWithError()
      • setUpWithError() ์™€ tearDownWithError() ๋Š” Xcode12์—์„œ ์ƒˆ๋กœ ์†Œ๊ฐœ๋จ.
      • ๊ธฐ์กด ๋ฒ„์ „ Xcode์—์„œ ์‚ฌ์šฉํ•˜๋˜ setUp(), tearDown() ๋„ ์‚ฌ์šฉ๊ฐ€๋Šฅ
  • test*() : test ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ test case๊ฐ€ ๋œ๋‹ค.
    • ํ•˜๋‚˜์˜ Test Case์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ•˜๋‚˜์˜ XCTAssert* ๊ฐ€ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค.
    • XCTAssert* ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ํ•ด๋‹น Test case๋Š” ์„ฑ๊ณต์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.
  • @testable import
    • import๋œ ๋ชจ๋“ˆ์˜ internal ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ด ์ง„๋‹ค. (์ผ๋ฐ˜์ ์ธ import์—์„œ๋Š” public ๋งŒ ๊ฐ€๋Šฅ)
    • fileprivate, private ์€ ์—ฌ์ „ํžˆ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.

Assertion

๋ชจ๋“  Test case๋Š” ํŠน์ • ์กฐ๊ฑด(condition)์œผ๋กœ ์š”์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค.

XCTAssert(result == expected, "๊ฒฐ๊ณผ์™€ ์˜ˆ์ธก์ด ๊ฐ™์•„์•ผ ํ•จ")

๋‹ค์–‘ํ•œ Assertion ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์‹คํŒจ์‹œ ์–ด๋–ค ์ด์œ ๋กœ ์‹คํŒจํ–ˆ๋Š”์ง€ ์ข€๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์œ„ ์˜ˆ์‹œ์ฒ˜๋Ÿผ message๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๋ฐฉ๋ฒ•์ด๋‹ค.

categoryfunction name
EqualityXCTAssertEqual, XCTAssertNotEqual
TruthinessXCTAssertTrue, XCTAssertFalse
NullabilityXCTAssertNil, XCTAssertNotNil
ComparisonXCTAssertLessThan, XCTAssertGreaterThan,
XCTAssertLessThanOrEqual, XCTAssertGreaterThanOrEqual
ErroringXCTAssertThrowsError, XCTAssertNoThrow
SpeacialXCTFail : ํ•ญ์ƒ ์‹คํŒจ
XCTUnwrap: expression์ด nil์ด๋ฉด ์‹คํŒจ, nil์ด ์•„๋‹ˆ๋ฉด unwrapped value ๋ฐ˜ํ™˜

์ž‘์„ฑ ๋ฐฉ๋ฒ•

  • Given
    • ์–ด๋– ํ•œ ์ƒํ™ฉ์—์„œ
  • When
    • ์–ด๋–ค ํ–‰๋™์„ ์ทจํ•  ๋•Œ
  • Then
    • Assertion
    • ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ผ
func testSplit_useDefaultSeparator_splitWords_Success() throws {
    // Given
    let text = "๊ธฐ๋ณธ ํŒŒ๋ผ๋ฏธํ„ฐ ํ…Œ์ŠคํŠธ"
 
    // When (use default separator: space)
    let result = try? split(text)
 
    // Then
    XCTAssertNotNil(result)
    XCTAssertEqual(result, ["๊ธฐ๋ณธ", "ํŒŒ๋ผ๋ฏธํ„ฐ", "ํ…Œ์ŠคํŠธ"])
}

Expectation

๋น„๋™๊ธฐ ๋™์ž‘์˜ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

func asyncFunction(with completion: @escaping (Int) -> Void) {
    let someParallelTask = {
        // write code
    }
    DispatchQueue.global().async {
        let result = someParallelTask()
        DispatchQueue.main.async {
            completion(result)
        }
    }
}

ํŠน์ • ํ•จ์ˆ˜ ์‹คํ–‰์‹œ, global queue์—์„œ ๋™์ž‘ ์‹คํ–‰ ํ›„, main์—์„œ ํ™”๋ฉด์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ completion code๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ์–ด๋–ป๊ฒŒ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์„๊นŒ?

func test_asyncFunction() {
    var result = 3.6
    asyncFunction { result = $0 } // ๊ณ„์‚ฐ ํ›„ ๊ฐ’์„ ๋ฐ˜์˜
    XCTAssertEqual(result, 3.6) // ๊ฒฐ๊ณผ์™€ ์˜ˆ์ƒ ๊ฐ’ ๋น„๊ต
}

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ–ˆ๋‹ค๋ฉด, ์‹คํŒจํ•œ๋‹ค. @escaping closure์˜ ์‹คํ–‰ ์‹œ์ ์„ ํ˜ธ์ถœ ์‹œ์ ์— ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. completion์ด ํ˜ธ์ถœ๋˜๊ธฐ ์ „ ํ…Œ์ŠคํŠธ๊ฐ€ ์ข…๋ฃŒ๋œ๋‹ค.

XCTestExpectation

func test_asyncFunction_with_expectation() {
    var result = 3.6
    let expectation = expectation(description: "asyncFunction")
    asyncFunction { calculatedResult in 
        result = calculatedResult
        expectation.fulfill() // ๋‚˜ ๊ฒฐ๊ณผ ๋ฐ›์•˜์–ด!!
    }
 
    wait(for: [expectation], timeout: 2) // ํ•ด๋‹น ์Šค๋ ˆ๋“œ๋ฅผ ๊ธฐ๋‹ค๋ ค์ค˜! 2์ดˆ ์ดํ›„์—๋Š” time์•„์›ƒ!
    XCTAssertEqual(result, 3.6)
}

XCTestExpectation์€ ์ฃผ์˜์‚ฌํ•˜์ž‰ ์žˆ๋Š”๋ฐ, ํ˜„์žฌ์™€ ๊ฐ™์€ ํ๋ฆ„์œผ๋กœ ์งœ๋Š” ๊ฒƒ์ด best practice์ด๋‹ค. ์ฆ‰, ๋น„๋™๊ธฐ task์•ˆ์—์„œ fullfill ํ˜ธ์ถœํ•˜๊ณ , wait๋กœ ๊ธฐ๋‹ค๋ ค์ฃผ๊ณ , XCTAssert๋กœ error, condition ํ™•์ธํ•˜๋Š” ์ˆœ์„œ๋กœ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

๋˜ ์ˆ˜ํ–‰์‹œ๊ฐ„ ์ž์ฒด๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ชฉ์ ์ด๋ผ๋ฉด timeout์„ test ์‹คํŒจ ์‹ ํ˜ธ๋กœ ์žก๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์ง€๋งŒ, ์ด ์ž์ฒด๋ฅผ ํ•ด๋‹น test case์˜ ์‹คํŒจ ์‹ ํ˜ธ๋กœ ์žก๋Š” ๊ฒƒ์€ ์ข‹์ง€ ๋ชปํ•˜๋‹ค. ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜์˜ ๋™์ž‘ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Other Expectations

  • XCTKVOExpectation
    • Observingํ•˜๋Š” keyPath์˜ ๊ฐ’์ด expectedValue๊ฐ€ ๊ฐ™์•„์ง„ ๊ฒฝ์šฐ
    • ๋“ฑ๋กํ•œ Handler๋ฅผ ๋งŒ์กฑํ•˜๋ฉด ์ž๋™์œผ๋กœ fulfill
  • XCTNSPredicateExpectation
    • Predicate ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด ์ž๋™์œผ๋กœ fulfill
  • XCTNSNotificationExpectation
    • ํŠน์ • Notification์ด post๋˜๋ฉด ์ž๋™์œผ๋กœ fulfill

Test Double (๋Œ€์—ญ)

์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ์—์„œ Production ๊ฐ์ฒด ๋Œ€์‹  ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

์ด๋Ÿฐ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๋ณต์žก๋„๋ฅผ ์ค„์ด๊ณ , ๋…๋ฆฝ์ ์œผ๋กœ ์ฝ”๋“œ ๊ฒ€์ฆ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค.

Fake

Production ์šฉ์€ ์•„๋‹ˆ๋‚˜ ๋™์ž‘์ด ๊ตฌํ˜„๋œ ๊ฐ์ฒด

๋ณดํ†ต Production ์ฝ”๋“œ์˜ ๊ฐ„๋žตํ™”๋œ ๋ฒ„์ „์œผ๋กœ ๋˜์–ด ์žˆ๋‹ค.

  • In-memory๋กœ ๊ตฌํ˜„ํ•œ database
    • ์‹ค์ œ database์™€ ๊ด€๋ จ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์—, ์š”์ฒญ ์‘๋‹ต ์‹œ๊ฐ„ ๋“ฑ์˜ ์™ธ๋ถ€์  ์š”์†Œ์˜ ์˜ํ–ฅ ์—†์ด ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

Stub

๋ฏธ๋ฆฌ ์ •์˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋“ค๊ณ  ์žˆ๋‹ค๊ฐ€ ํ…Œ์ŠคํŠธ ์ค‘ ์š”์ฒญ์— ๋”ฐ๋ผ ๊ทธ ๊ฐ’์„ ์‘๋‹ตํ•˜๋Š” ๊ฐ์ฒด

์‹ค์ œ DB๋‚˜ ๋„คํŠธ์›Œํฌ์— ์ ‘๊ทผํ•˜์ง€ ์•Š๊ณ , ์ƒํ™ฉ์— ๋งž๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

Mock

์ˆ˜์‹ ๋œ ์š”์ฒญ์„ ๊ธฐ๋กํ•˜๋Š” ๊ฐ์ฒด

Mock์— ์˜ˆ์ƒ๋œ action์ด ์ˆ˜ํ–‰๋˜์—ˆ๋Š”์ง€ ๊ฒ€์ฆํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ•จ์ˆ˜ ํ˜ธ์ถœ์‹œ count๋˜๋Š” flag๋ฅผ ๋‹ฌ์•„์„œ, ํ•ด๋‹น flag๊ฐ’์„ ํ™•์ธํ•œ ๊ฒƒ.

์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์‹ซ๊ฑฐ๋‚˜ ์˜๋„๋œ ์ฝ”๋“œ๊ฐ€ ์‹ค์ œ ์ˆ˜ํ–‰๋˜์—ˆ๋Š”์ง€ ๊ฒ€์ฆํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ์‹ค์ œ ์ด๋ฉ”์ผ์ด ๋ฐœ์†ก๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์—, ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ (count)ํ™•์ธํ•˜๋Š” ์ •๋„๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

Command Query Separation

Logic๊ณผ Effect๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. (Bertrand Meyer โ€œObject Oriented Software Constructionโ€)

func averageGrades(sudent: Student) -> Double

์‹œ์Šคํ…œ์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” method๋ฅผ Query๋ผ ํ•œ๋‹ค. ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์—†์ด ๊ฐ’์„ ๋ฆฌํ„ดํ•œ๋‹ค. ์ด์™€ ๊ฐ™์€ Query ํ˜•ํƒœ์˜ ๋ฉ”์„œ๋“œ๋ฅผ Stub์„ ์‚ฌ์šฉํ•˜์—ฌ Test Doubleํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ๊ฐ’์„ ๋“ค๊ณ  ์žˆ๋‹ค๊ฐ€ ์‘๋‹ตํ•˜์—ฌ testํ•  ์ˆ˜ ์žˆ๋‹ค.

func sendRemiderEmail(sudent: Student)

Command๋Š” ์–ด๋–ค action์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ์‹œ์Šคํ…œ์˜ ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ๋ฉด์„œ, ๊ฐ’์„ ๋ฆฌํ„ดํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งํ•œ๋‹ค. ์œ„์˜ ์˜ˆ์‹œ์˜ ๊ฒฝ์šฐ ๋ฆฌํ„ดํ•˜์ง€ ์•Š๊ณ , ์‹œ์Šคํ…œ์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” Mock์„ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

Tips

  • ์ดˆ๊ธฐํ™”๋ฅผ ์ž˜ํ•œ๋‹ค.

    • setUp(), tearDown()์—์„œ ์ดˆ๊ธฐํ™”๋ฅผ ์ž˜ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.
    • class level์˜ ์ƒํƒœ๋Š” ๊ณผ์ •์ค‘์— ๊ณ„์† ์œ ์ง€๋˜๊ธฐ ๋•Œ๋ฌธ์— ์›์น˜์•Š์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
    • ์‹คํ–‰ ์ˆœ์„œ์— ์˜์กด์ ์ธ ๊ฒฝ์šฐ, ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. TC๋Š” ๋…๋ฆฝ์ ์ด์–ด์•ผ ํ•œ๋‹ค.
  • ๋””๋ฒ„๊น… ์ž˜ํ•˜๊ธฐ

    • Given์˜ ๊ฐ€์ •์„ ์ž˜ ํ™•์ธํ•œ๋‹ค.
    • Then์—์„œ ์˜๋„ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ •ํ™•ํžˆ ๋ฐ˜์˜ํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
    • Test BreakPointer Break poiunt๋ฅผ ๋‹ฌ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ test Failure Breakpoint๋ฅผ ์„ ํƒํ•œ๋‹ค.
      • ํ…Œ์ŠคํŠธ ์‹คํŒจ ์ง€์ ์— ์ž๋™์œผ๋กœ breakpoint๋ฅผ ๊ฑธ์–ด์ค€๋‹ค.
  • ์ž„์‹œ ํ…Œ์ŠคํŠธ (Pragmatic Programming)

    • ๋””๋ฒ„๊น… ํ•˜๋ฉด์„œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ•ด๋ณด๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.
    • ์ด๋Ÿฐ ๊ฒฝ์šฐ ์ •์‹ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ๋งŒ๋“ค์–ด ๋‘์–ด์•ผ ํ•œ๋‹ค.
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์กฐ์งํ™”

    • ์˜ˆ์‹œ
    Test Target
    โŽฃ Cases
        โŽฃ Group 1
            โŽฃ Tests 1
            โŽฃ Tests 2
        โŽฃ Group 2
            โŽฃ Tests
    โŽฃ Mocks
    โŽฃ Helper Classes
    โŽฃ Helper Extension
    
  • Xcode

    • ์‹คํ–‰ ์ˆœ์„œ randomize ์˜ต์…˜์ด ์žˆ๋‹ค.
      • Xcode > Edit Scheme > Test > Info > Options > Randomize execution order
    • Code Coverage
      • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ๊ฒ€์ฆํ•œ ์ฝ”๋“œ ๋ฒ”์œ„๋ฅผ reporting ํ•ด์ค€๋‹ค.
      • Xcode > Edit Scheme > Test > Optinos > Code Coverage

Reference