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

[iOS/Swift] Unit Test ๋ž€?

by ํ‹ด๋”” 2023. 4. 10.
728x90
๋ฐ˜์‘ํ˜•
  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ผ๊ณ  ํ•˜๋ฉฐ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ธฐ๋ณธ ๋‹จ์œ„์ธ ๋ชจ๋“ˆ์„ ํ…Œ์ŠคํŠธ ํ•จ
  • ๋ชจ๋“ˆ์ด ์ •ํ•ด์ง„ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ ํ•จ(๋ชจ๋“ˆ ๋‹จ์œ„๋กœ ์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋˜์–ด์•ผ ํ•จ)

FIRST ๊ธฐ์ค€

  • Fast(๋น ๋ฆ„) 
    • ํ…Œ์ŠคํŠธ๋Š” ๋น ๋ฅด๊ฒŒ ์‹คํ–‰๋˜์–ด์•ผ ํ•จ
  • Independent/Isolated(๊ณ ๋ฆฝ๋จ)
    • ํ…Œ์ŠคํŠธ๋Š” ์„œ๋กœ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•ด์„œ๋Š” ์•ˆ๋จ
  • Repeatable(๋ฐ˜๋ณต์ )
    • ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์–ด์•ผ ํ•จ.
    • ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต๊ธ‰์ž(external data Provider ๋„คํŠธ์›Œํฌ ์„œ๋น„์Šค ๋กœ์ง ๊ฐ™์€ ๊ฒƒ), ๋™์‹œ์„ฑ(concurrency) ๋ฌธ์ œ๋กœ ์ธํ•ด ๊ฐ„ํ—์  ์˜ค๋ฅ˜ ๋ฐœ์ƒ ํ•  ์ˆ˜ ์žˆ์Œ
  • Self-validating(์ž๊ฐ€ ๊ฒ€์ฆ) 
    • ํ…Œ์ŠคํŠธ๋Š” ์™„์ „ํžˆ ์ž๋™ํ™”๋˜์–ด์•ผ ํ•จ.
    • ๋กœ๊ทธํŒŒ์ผ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ํ•ด์„ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ๋Œ€ํ•ด “ํ†ต๊ณผ” ๋˜๋Š” “์‹คํŒจ”์—ฌ์•ผํ•จ
  • Timely(์ ์‹œ)
    • ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ TDD
    • ์ด์ƒ์ ์œผ๋กœ๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  production ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ํ•จ

์˜ˆ์‹œ ์ฝ”๋“œ

class LoginTests: XCTestCase {
    
    func testLoginButtonEnabledWithValidCredentials() {
        // Given
        let viewController = LoginViewController()
        let usernameField = UITextField()
        let passwordField = UITextField()
        let loginButton = UIButton()
        
        viewController.usernameField = usernameField
        viewController.passwordField = passwordField
        viewController.loginButton = loginButton
        
        // When
        usernameField.text = "john.doe@example.com"
        passwordField.text = "password123"
        
        // Then
        XCTAssertTrue(loginButton.isEnabled)
    }
    
    func testLoginButtonDisabledWithInvalidCredentials() {
        // Given
        let viewController = LoginViewController()
        let usernameField = UITextField()
        let passwordField = UITextField()
        let loginButton = UIButton()
        
        viewController.usernameField = usernameField
        viewController.passwordField = passwordField
        viewController.loginButton = loginButton
        
        // When
        usernameField.text = "invalid-username"
        passwordField.text = "invalid-password"
        
        // Then
        XCTAssertFalse(loginButton.isEnabled)
    }
}

๋ฉ”์„œ๋“œ ๊ทœ์น™

  • ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์€ test๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•จ(๊ทธ๋ž˜์•ผ ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Œ)
  • test ํ”„๋ฆฌํ”ฝ์Šค ๋’ค์— ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ ์Œ

๋ฉ”์„œ๋“œ ๋‚ด๋ถ€ ์„น์…˜

  • Given
    • ํ•„์š”ํ•œ ๊ฐ’์„ ์„ค์ •
  • When
    • ํ…Œ์ŠคํŠธ ์ค‘์ธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰
  • Then
    • ์˜ˆ์ƒํ•œ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ์ˆ ํ•˜๋Š” ์„น์…˜
    • XCTestAssertions๋ฅผ ์‚ฌ์šฉํ•จ

 

์žฅ์ 

  • ์ฝ”๋“œ์˜ ๋ชจ๋“ˆํ™”
  • ์ฝ”๋“œ๋ฅผ ๋…๋ฆฝ์ ์ด๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
  • ๋ฆฌํŒฉํ† ๋ง ๊ฐ€๋Šฅ
  • ๊ฐœ๋ฐœ -> ํ…Œ์ŠคํŠธ -> ๋ฐฐํฌ ์ž๋™ํ™” ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•๊ฐ€๋Šฅ
  • ๋ชจ๋“ˆ ๋‹จ์œ„์˜ ํ…Œ์ŠคํŠธ => ์•ฑ ์ „์ฒด ๋นŒ๋“œ x, ๋ชจ๋“ˆ ๋ณ„๋กœ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ

๋‹จ์ 

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

 

Photo by Chokniti Khongchum from Pexels: https://www.pexels.com/photo/person-holding-glass-flasks-3082451/

 

์ฐธ๊ณ  ์‚ฌ์ดํŠธ ๋ฐ ์ถœ์ฒ˜

UnitTest: https://ios-development.tistory.com/334

UITest : http://yoonbumtae.com/?p=4020

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€