๐ŸŽ iOS/UI

[iOS] UI Test ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

Fomagran ๐Ÿ’ป 2021. 7. 20. 12:32
728x90
๋ฐ˜์‘ํ˜•

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

 

์ €๋ฒˆ ํฌ์ŠคํŒ…์—” Unit Test์— ๋Œ€ํ•ด์„œ ๋‹ค๋ค˜๋Š”๋ฐ์š”

 

์˜ค๋Š˜์€ UI๋ฅผ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋Š” UI Test์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌ๋ฅผ ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค

 

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


UITest Bundle ๋งŒ๋“ค๊ธฐ

 

Project - General ํƒญ์œผ๋กœ ์ด๋™ํ•˜์…”์„œ ์™ผ์ชฝ ํ•˜๋‹จ ๋ถ€๋ถ„์— +๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”.

 

 

๊ทธ๋ฆฌ๊ณค ui๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  UI Testing Bundle์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”.

 


Storyboard

 

์•„๋ž˜์™€ ๊ฐ™์ด ํšŒ์›๊ฐ€์ž… ํ•˜๋Š” ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๊ตฌ์„ฑํ• ๊ฑด๋ฐ์š”.

 

์ด๋ฉ”์ผ ํ…์ŠคํŠธํ•„๋“œ,๋น„๋ฐ€๋ฒˆํ˜ธ ํ…์ŠคํŠธํ•„๋“œ,๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ํ…์ŠคํŠธํ•„๋“œ,ํšŒ์›๊ฐ€์ž… ๋ฒ„ํŠผ์œผ๋กœ ๊ตฌ์„ฑํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 


SignupViewController

 

IBOutlet์„ ๋ชจ๋‘ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๊ณ 

 

signupButton์„ ๋ˆŒ๋ €์„ ๋•Œ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ํ™•์ธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฅด๋‹ค๋ฉด ๊ฒฝ๊ณ ์ฐฝ์„ ๋„์šฐ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

  @IBOutlet weak var signupButton: UIButton!
  @IBOutlet weak var repeatTF: UITextField!
  @IBOutlet weak var passwordTF: UITextField!
  @IBOutlet weak var emailTF: UITextField!
  
    @IBAction func tapSignupButton(_ sender: Any) {        
        if passwordTF.text != repeatTF.text {
            let alert = UIAlertController(title: "Error", message:"๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ํ™•์ธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            DispatchQueue.main.async {
                //ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด accessibilityIdentifier๋ฅผ ์ •ํ•ด์ค˜์•ผํ•จ
                alert.view.accessibilityIdentifier = "errorAlertDialog"
                self.present(alert, animated: true, completion: nil)
            }
        }
    }

UITests

 

UI Test Case Classs๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์‹œ๊ณ  

 

์ด๋ฆ„์€ SignupFlowUITests๋กœ ์ง“๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

์ƒ์„ฑ ์‹œ ๋ฐ˜๋“œ์‹œ UITests๋ฅผ ์ฒดํฌํ•ด์ฃผ์„ธ์š”.

 

 

์•„๋ž˜์™€ ๊ฐ™์ด ํ™”๋ฉด์— ์žˆ๋Š” ๋ชจ๋“  ์š”์†Œ๋“ค์„ ์„ธํŒ…ํ•ด์ค๋‹ˆ๋‹ค.

 

class SignupFlowUITests: XCTestCase {
    
    private var app:XCUIApplication!
    private var emailTF:XCUIElement!
    private var passwordTF:XCUIElement!
    private var repeatPasswordTF:XCUIElement!
    private var signupButton:XCUIElement!

 

๊ทธ๋ฆฌ๊ณค setupWithError ๋ฉ”์†Œ๋“œ์— ๋ชจ๋“  ์š”์†Œ๋“ค์˜ ๊ฐ’์„ ๋„ฃ์–ด์ค„๊ฑด๋ฐ์š”.

 

์—ฌ๊ธฐ์„œ app.textFields[identifier] ๋ถ€๋ถ„์€ identifier๋ฅผ ์ •ํ•ด์ค๋‹ˆ๋‹ค.

 

override func setUpWithError() throws {
        try super.setUpWithError()
        continueAfterFailure = false
        
        app = XCUIApplication()
        app.launch()
        
        emailTF = app.textFields["emailTF"]
        passwordTF = app.textFields["passwordTF"]
        repeatPasswordTF = app.textFields["repeatPasswordTF"]
        signupButton = app.buttons["signupButton"]
        
    }

 

element์˜ identifier๋ฅผ ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์šฐ์„  ์Šคํ† ๋ฆฌ๋ณด๋“œ๋กœ ์ด๋™ํ•˜์‹  ๋’ค

 

์˜ค๋ฅธ์ชฝ 4๋ฒˆ์งธ ํƒญ์„ ํด๋ฆญํ•˜์‹œ๊ณ  ์•„๋ž˜๋กœ ๋‚ด๋ฆฌ๋ฉด

 

์•„๋ž˜์™€ ๊ฐ™์ด Accessibility๊ฐ€ ์žˆ์„๊ฑฐ์—์š”.

 

์—ฌ๊ธฐ์„œ Identifier๋ฅผ ์ •ํ•ด์ค๋‹ˆ๋‹ค.

 

 

Identifier๋ฅผ ์ •ํ•˜์ง€ ์•Š๊ณ  ํ•˜๋ ค๋ฉด 

 

UITests ํŒŒ์ผ์˜ ์˜ค๋ฅธ์ชฝ ํ•˜๋‹จ์„ ๋ณด๋ฉด ๋นจ๊ฐ„์ƒ‰ ๋™๊ทธ๋ผ๋ฏธ ๋ฒ„ํŠผ์ด ์žˆ์„๊ฑฐ์—์š”.

 

 

์ด๊ฑธ ํด๋ฆญํ•˜์‹œ๋ฉด ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๊ฐ€ ๋œฐ๊ฑด๋ฐ

 

์—ฌ๊ธฐ์„œ ์›ํ•˜์‹œ๋Š” ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ”Œ๋ ˆ์ด์Šคํ™€๋” ์ด๋ฆ„์œผ๋กœ ์š”์†Œ๊ฐ€ ํƒ€์ดํ•‘๋˜๊ณ  ์–ด๋–ค ํ–‰๋™์„ ํ•˜์˜€๋Š”์ง€๋„ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

 

  XCUIApplication().textFields["email"].tap()
  XCUIApplication().textFields["Password"].tap()
  XCUIApplication().textFields["Repeat Password"].tap()

 

๋ณธ๊ฒฉ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ €๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ํ™•์ธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฅด๋ฉด ๊ฒฝ๊ณ ์ฐฝ์„ ๋„์šฐ๋ผ๊ณ  SignupViewController์—์„œ ๊ตฌํ˜„ํ•ด๋†“์•˜์ฃ ?

 

๊ทธ๋ž˜์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ํ™•์ธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฅด๋ฉด ๊ฒฝ๊ณ ์ฐฝ์„ ๋„์šฐ๋Š”์ง€ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์–ด๋– ํ•œ ํ–‰๋™์„ ํ•˜๋ผ๊ณ  ๋ช…๋ น์„ ๋‚ด๋ฆฌ๊ณ  ๊ทธ์— ๋งž๋Š” ๊ฒฐ๊ณผ๊ณผ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•ด์ค๋‹ˆ๋‹ค.

 

์ด๋ฉ”์ผ ํ…์ŠคํŠธํ•„๋“œ๋ฅผ ํƒญํ•˜๊ณ  ์ด๋ฉ”์ผ์„ ์ž…๋ ฅ

 

ํŒจ์Šค์›Œ๋“œ ํ…์ŠคํŠธํ•„๋“œ๋ฅผ ํƒญํ•˜๊ณ  ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ž…๋ ฅ

 

ํ™•์ธ ํŒจ์Šค์›Œ๋“œ ํ…์ŠคํŠธํ•„๋“œ๋ฅผ ํƒญํ•˜๊ณ  ํ™•์ธ ํŒจ์Šค์›Œ๋“œ ์ž…๋ ฅ

 

ํšŒ์›๊ฐ€์ž… ๋ฒ„ํŠผ ํƒญ์„ ํ•œ ๋’ค ๊ฒฝ๊ณ ์ฐฝ์ด ๋œจ๋Š”์ง€ ํ™•์ธ

 

 

    func testSignupViewController_DonotMatchPasswordAndRepeatPassword_PresentErrorAlertDialog() {
        
        //Act
        emailTF.tap()
        emailTF.typeText("fomagran6@naver.com")
        
        passwordTF.tap()
        passwordTF.typeText("12345678")
        
        repeatPasswordTF.tap()
        repeatPasswordTF.typeText("123456")
        
        signupButton.tap()
        
        //Assert
        XCTAssertTrue(app.alerts["errorAlertDialog"].waitForExistence(timeout: 1),"์ž˜๋ชป๋œ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๊ฒฝ๊ณ ์ฐฝ์ด ๋– ์•ผํ•˜๋Š”๋ฐ ์•ˆ๋–ด์–ด์š”")
    }

 

cmd + u ๋ฅผ ๋ˆŒ๋Ÿฌ์„œ ํ™•์ธํ•ด๋ณด๋ฉด 

 

์ œ๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ํƒ€์ดํ•‘์„ ํ•˜๊ณ  ์ž๋™์œผ๋กœ ํƒญ์„ ํ•˜๋ฉด์„œ ๊ฒฝ๊ณ ์ฐฝ์ด ๋œจ๋Š”์ง€ ์•ˆ๋œจ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

 

(์ง„์งœ ๋„ˆ๋ฌด๋„ˆ๋ฌด ์‹ ๊ธฐํ•˜๋”๋ผ๊ตฌ์š”...)

 

 

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ํŒจ์Šค์›Œ๋“œ์™€ ํ™•์ธ ํŒจ์Šค์›Œ๋“œ๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ์ž…๋ ฅ๋์„ ๋•Œ ๊ฒฝ๊ณ ์ฐฝ์ด ๋–ด์œผ๋‹ˆ ํ†ต๊ณผ๊ฐ€ ๋œ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


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

 

UI ํ…Œ์ŠคํŠธ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์–ด๋– ํ•œ ํ๋ฆ„์„ ์ •ํ•ด๋†“๊ณ  ์ด๊ฒƒ์— ๋งž๊ฒŒ ํ–‰๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

์–ด๋– ํ•œ ํ–‰๋™์„ ์ •ํ•ด์ฃผ๊ณ  ์ž๋™์œผ๋กœ ์‹คํ–‰ํ•˜๊ฒŒ ํ•œ ๋’ค ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์ด ๋„ˆ๋ฌด ์‹ ๊ธฐํ•˜๊ณ  ํŽธํ•˜๋”๋ผ๊ตฌ์š”.

 

(ํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ๊นŒ์ง€๊ฐ€ ๋„ˆ๋ฌด ๋ถˆํŽธํ•˜์ง€๋งŒ...ใ…Ž)

 

์•ž์œผ๋กœ๋Š” ์ด๋ ‡๊ฒŒ ํ๋ฆ„์„ ๋ฏธ๋ฆฌ ์„ค๊ณ„ํ•ด๋ณด๊ณ  ๋งž๊ฒŒ ํ–‰๋™ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•ด๋ณธ ๋’ค ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์Šต๊ด€์„ ๊ธธ๋Ÿฌ์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

ํ˜น์‹œ๋ผ๋„ ๊ถ๊ธˆํ•˜์‹  ๋ถ€๋ถ„์ด๋‚˜ ์ง€์ ํ•ด์ฃผ์‹ค ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์„ธ์š”!

 

728x90
๋ฐ˜์‘ํ˜•