๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS/iOS

[iOS] Unit Test์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํžˆ ์•Œ์•„๋ณด๊ธฐ

by Fomagran ๐Ÿ’ป 2021. 7. 19.
728x90
๋ฐ˜์‘ํ˜•

 

์•ˆ๋…•ํ•˜์„ธ์š” Foma๐Ÿ‘Ÿ ์ž…๋‹ˆ๋‹ค!

 

์˜ค๋Š˜์€ Xcode์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ๋‹›ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์˜ˆ์ „๋ถ€ํ„ฐ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ์ค‘์š”์„ฑ์€ ์ •๋ง ๊ฐ•์กฐ๋˜์—ˆ๊ณ  ์ €๋„ ํ•ด์•ผ์ง€...ํ•ด์•ผ์ง€.. ํ•˜๋ฉด์„œ ๋ฏธ๋ฃจ๋‹ค๊ฐ€

 

์ด์ œ์•ผ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•ด๋ณด๊ณ  ๊ณต๋ถ€ํ•œ ๊ฒƒ๋“ค์„ ์ •๋ฆฌํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

๋ฐ”๋กœ ์‹œ์ž‘ํ• ๊ฒŒ์š”~


Unit Test Bundle ๋งŒ๋“ค๊ธฐ

 

๋จผ์ € ์œ ๋‹›ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์ด ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์‹œ์— Include Tests ์ฒดํฌํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

 

๋งŒ์•ฝ์— ์ด๊ฑฐ ํ”„๋กœ์ ํŠธ๋ฅผ ์ด๋ฏธ ๋งŒ๋“ค์–ด๋ฒ„๋ ธ๋‹ค๋ฉด Project - General ํƒญ์œผ๋กœ ์ด๋™ํ•˜์‹ ๋’ค ์™ผ์ชฝ ํ•˜๋‹จ ๋ถ€๋ถ„์— + ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”.

 

 

๊ทธ ๋‹ค์Œ Unit์„ ๊ฒ€์ƒ‰ํ•˜์‹œ๋ฉด Unit Testing Bundle์ด ์žˆ์„๊ฑฐ์—์š” ์ด๊ฑธ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

 


Unit Test ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ

 

UnitTest ExampleTests๊ฐ€ ์ƒ๊ฒผ์„๊ฑฐ์—์š”.

 

 

cmd + n ์„ ๋ˆ„๋ฅด์‹œ๊ณ  Unit Test Case Class ํŒŒ์ผ์„ ์„ ํƒํ•ด์ค๋‹ˆ๋‹ค.

 

 

๊ทธ๋ฆฌ๊ณ  ์ด๋ฆ„์€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ณ ์‹ถ์€ ํŒŒ์ผ + Tests๋กœ ์ง“์Šต๋‹ˆ๋‹ค.

 


Unit Test ์ดˆ๊ธฐ ๋ฉ”์†Œ๋“œ

 

์ด๋ ‡๊ฒŒ 4๊ฐ€์ง€ ๋ฉ”์†Œ๋“œ๊ฐ€ ๋งŒ๋“ค์–ด์งˆํ…๋ฐ์š”.

 

  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.
        }
    }

 

1. setUpWithError

 

ํ…Œ์ŠคํŠธ์—์„œ ๊ฐ€์žฅ ๋จผ์ € ์‹คํ–‰๋˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ๋ณดํ†ต ์–ด๋–ค ๋ชจ๋ธ์ด๋‚˜ ์‹œ์Šคํ…œ์„ ์ •์˜ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

2. tearDown

 

ํ…Œ์ŠคํŠธ์—์„œ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ์‹คํ–‰๋˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ๋ณดํ†ต ์ •์˜ํ–ˆ๋˜ ๊ฒƒ๋“ค ํ•ด์ œ์‹œํ‚ค๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

3.testExample

 

ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

4. testPerformanceExample

 

์„ฑ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์ฝ”๋“œ์˜ ์‹คํ–‰ ์†๋„๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.


LoginValidator

 

ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ ค๋ฉด ์‹ค์ œ Validator๊ฐ€ ์žˆ์–ด์•ผ๊ฒ ์ฃ ?

 

๊ฐ„๋‹จํ•˜๊ฒŒ ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ์˜ ๊ธธ์ด๋กœ๋งŒ ์ฒดํฌํ•ด์ฃผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

class LoginValidator {
    
    func isValidEmail(email:String) -> Bool {
         return email.contains("@")
    }
    
    func isValidPasword(password:String) -> Bool {
        return password.count < 5
    }
    
}

LoginValidatorTests

 

๊ทธ ๋‹ค์Œ LoginValidatorTests๋กœ ๋Œ์•„์™€์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ํ”„๋กœ์ ํŠธ๋ฅผ @testable๊ณผ import ํ•ด์ค๋‹ˆ๋‹ค.

 

@testable import UnitTest_Example

 

ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ดˆ๊ธฐ ์„ธํŒ…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

(์—ฌ๊ธฐ์„œ sut๋Š” systemUnderTest์˜ ์ค„์ž„๋ง๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.)

 

class LoginValidatorTests: XCTestCase {
    
    var sut:LoginValidator!
    
    override func setUpWithError() throws {
        sut = LoginValidator()
      }

      override func tearDownWithError() throws {
        sut = nil
      }
}

ํ…Œ์ŠคํŠธ ์ด๋ฆ„ ์ž‘์„ฑ๋ฒ•

 

๊ทธ๋ฆฌ๊ณค ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ๋ฉ”์†Œ๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๋Š”๋ฐ์š”.

 

์—ฌ๊ธฐ์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์˜ ์ด๋ฆ„์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

1. ์•ž์— test๋ฅผ ๋ถ™์ด๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ํด๋ž˜์Šค ์ด๋ฆ„์„ ์ ์–ด์ค€๋‹ค.

 

2. ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ƒํ™ฉ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•œ๋‹ค.

 

3. ์˜ˆ์ƒ๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ ์–ด์ค€๋‹ค.

 

์ฆ‰, ๋กœ๊ทธ์ธ๋ฐธ๋ฆฌ๋ฐ์ดํ„ฐ๋ฅผ ํ…Œ์ŠคํŠธํ• ๊ฑฐ์•ผ _ ์˜ฌ๋ฐ”๋ฅธ์ด๋ฉ”์ผ์ด ์ฃผ์–ด์กŒ์„๋•Œ _ ๋„Œ True๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ๋ผ ๋ผ๊ณ  ์ง“๋Š” ๊ฒƒ์ด์ฃ .

 

 func testLoginValidator_WhenValidEmailProvided_ShouldReturnTrue() {
        
    }

Test ์ž‘์„ฑ๋ฒ•

 

๋จผ์ € ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „์— User ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

struct User {
    let email:String
    let password:String
    
    init(email:String,password:String) {
        self.email = email
        self.password = password
    }
}

 

ํ…Œ์ŠคํŠธ๋Š” Arrange - Act - Assert ์ˆœ์œผ๋กœ ์ž‘์„ฑํ•˜๋Š”๋ฐ์š”.

 

1. Arrange

ํ…Œ์ŠคํŠธ์— ํ•„์š”ํ•œ ํด๋ž˜์Šค๋‚˜ ๊ฐ์ฒด ๋“ฑ์„ ๋‚˜์—ดํ•ฉ๋‹ˆ๋‹ค.

2.Act

ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์–ด๋– ํ•œ ํ–‰๋™์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

 

3.Assert

Act๋ฅผ XCAssert์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. (,๋ฅผ ๋ถ™์ด๊ณ  ๋งŒ์•ฝ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์•˜์„ ๋•Œ๋ฅผ ์—๋Ÿฌ๋กœ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

 

func testLoginValidator_WhenValidEmailProvided_ShouldReturnTrue() {
        //Arrange
        let user = User(email: "Fomagran6@naver.com", password: "1234")
        
        //Action
        let isValidEmail = sut.isValidEmail(email: user.email)
        
        //Assert
        XCTAssertTrue(isValidEmail,XCTAssertTrue(isValidEmail,"isValidEmail์€ True๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ๋˜๋Š”๋ฐ False๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ์–ด @๋ฅผ ํฌํ•จ์‹œ์ผœ์•ผ ํ•ด!"))
    }

 

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•œ๋’ค ์™ผ์ชฝ์— ๋‹ค์ด์•„๋ชฌ๋“œ ๋ชจ์–‘์œผ๋กœ ๋นˆ ๋ฒ„ํŠผ์ด ๋ณด์ผ๊ฑฐ์—์š”.

 

 

๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์‹คํ–‰ํ•ด์ฃผ๋ฉด ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ• ๊ฑฐ์—์š”. (cmd + u ๋ฅผ ๋ˆŒ๋Ÿฌ๋„ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.)

 

ํ…Œ์ŠคํŠธ๊ฐ€ ์˜ˆ์ƒ๋˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋‚˜์™”๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ดˆ๋ก์ƒ‰์œผ๋กœ ์ฒดํฌ๋๋‹ค๊ณ  ๋œฐ๊ฑฐ์—์š”.

 

 

๋งŒ์•ฝ ์‹คํŒจํ–ˆ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋นจ๊ฐ„์ƒ‰ ์—‘์Šค๋ชจ์–‘์œผ๋กœ ์‹คํŒจํ–ˆ๋‹ค๊ณ  ๋œฐ๊ฑฐ์—์š”.

 

 

์™œ ์‹คํŒจํ–ˆ๋Š”์ง€ ์ž‘์„ฑํ•ด๋†“์•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์™œ ์‹คํŒจํ–ˆ๋Š”์ง€ ์•Œ๋ ค์ค„๊ฑฐ์—์š”.

 

 

(์ฐธ๊ณ ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์ˆœ์„œ๋Š” ๋‚˜์—ด๋œ ๋ฉ”์„œ๋“œ์˜ ์ˆœ์„œ๊ฐ€ ์•„๋‹ˆ๋ผ ์ž‘์„ฑ๋œ ์ด๋ฆ„์ˆœ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.)


Code Coverage

 

์ฝ”๋“œ ์ปค๋ฒ„๋ฆฌ์ง€๋ž€ ์‹ค์ œ๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ ์ค‘์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•œ ๋น„์œจ์„ ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ธ๋ฐ์š”.

 

Xcode ์™ผ์ชฝํƒญ ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰๋ฒˆ์งธ๋ฅผ ํƒญํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜์˜ฌํ…๋ฐ Coverage๋ฅผ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”.

 

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์›ํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ์–ด๋Š ์ •๋„ ํ…Œ์ŠคํŠธ๊ฐ€ ์ž‘์„ฑ๋˜์—ˆ๋Š”์ง€ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

(์ด๋ฉ”์ผ์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ๊ณผ ํŒจ์Šค์›Œ๋“œ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๋Š”๋ฐ ์ €๋Š” ์œ„์—์„œ ์ด๋ฉ”์ผ์„ ์ฒดํฌํ•˜๋Š” ํ…Œ์ŠคํŠธ๋งŒ ์ž‘์„ฑํ–ˆ์œผ๋‹ˆ 50%๋กœ ๋‚˜์˜ค๋„ค์š”.)

 

 


์˜ค๋Š˜์€ ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ Unit Test๋ฅผ ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

ํ™•์‹คํžˆ Unit Test๋ฅผ ํ•ด์„œ ์›ํ•˜๋Š” ๋กœ์ง์ด ํ†ต๊ณผํ•˜๋‹ˆ๊น ๊ทธ๋งŒํผ ์•ˆ์ •์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋Š” ๋Š๋‚Œ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ํ•˜๋‚˜ ํ•˜๋‚˜ ์ž‘์„ฑํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๋‹ค๋ณด๋‹ˆ ์‹œ๊ฐ„์ด ๊ฝค ์˜ค๋ž˜๊ฑธ๋ฆฌ๊ณ ...๊ท€์ฐฎ๋”๋ผ๊ตฌ์š”...

 

๊ทธ๋ž˜๋„ ์•ˆ์ •์ ์ธ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„  ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๊ฝค ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€