39
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

XCTest入門 (Swift) ~UITest編~

Last updated at Posted at 2016-08-19

#はじめに
XCTestのUITestについて書きます。

XCTestのUnitTestについても以前投稿しています。見てみてください。
XCTest入門Part1 (Swift)
XCTest入門Part2 (Swift) ~非同期編~
XCTestでカバレッジを確認する

#UITestって何ができる?
UITestでは、名前の通りですが主に見た目の部分をテストすることができます。

例えば、「ある操作をしたら、あるアラートが表示されること」
などを簡単に確認できます。

#UITestの流れ
XCTestでUnitTestをする場合と同様に
各テスト前に処理をするメソッドと各テスト後に処理をするメソッドがあります。

setup( )
→各テストを実行する前に毎回呼ばれます。
tearDown( )
→各テスト実行後に毎回呼ばれます。

setup( )の中身がUnitTestの場合と少し異なります。
UITestの場合は、テスト前にアプリを起動する処理が必要です。

XCUIApplication().launch()

また、テスト失敗時にすぐテストを止めるかどうかを決める必要があります。
(基本的には、失敗時はすぐにテストを止めることが好ましいようです。)

continueAfterFailure = false

必要に応じて画面の向きなどもsetup( )の中で設定しておきます。

SwiftUITestSampleUITests.swift
override func setUp() {
    super.setUp()
        
    // test Failure時にすぐ止める (trueにすると、test失敗しても最後まで処理する)
    continueAfterFailure = false
        
    // セットアップ毎にアプリを起動
    XCUIApplication().launch()

    // 画面の向きなどを指定したい場合はここで設定しておく
}

各テスト実行後のtearDown( )は、今回は特に何も書いていません。

SwiftUITestSampleUITests.swift
override func tearDown() {
    super.tearDown()
}

#操作を記録する
XCTestのUITestは実際に操作した操作手順からテストコードを生成してくれる
機能があります。

右下の赤丸をクリックすると、シミュレータを起動して記録を開始します。
記録したい操作を実行しましょう。
スクリーンショット 2016-08-20 3.07.13.png

例として、
テキストフィールドをタップしてキーボードを表示し、
「123」と入力してキーボードを閉じる操作を記録しました。

生成されたコードがこちら。

SwiftUITestSampleUITests.swift
func testSample() {
        
    let app = XCUIApplication()
    let pleaseEnterHogeElementsQuery = app.otherElements.containingType(.StaticText, identifier:"Please enter \"hoge\"")
    pleaseEnterHogeElementsQuery.childrenMatchingType(.TextField).element.tap()
        
    let moreNumbersKey = app/*@START_MENU_TOKEN@*/.keys["more, numbers"]/*[[".keyboards.keys[\"more, numbers\"]",".keys[\"more, numbers\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/
    moreNumbersKey.tap()
    moreNumbersKey.tap()
    pleaseEnterHogeElementsQuery.childrenMatchingType(.TextField).element
    app/*@START_MENU_TOKEN@*/.buttons["Done"]/*[[".keyboards.buttons[\"Done\"]",".buttons[\"Done\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap()
    app.typeText("\n")
        
}

うーん、なんか違う。
コードを以下のように修正したら、記録した動作と同様の動作を再現出来ました!

SwiftUITestSampleUITests.swift
func testSample() {
        
    let app = XCUIApplication()
    let pleaseEnterHogeElementsQuery = app.otherElements.containingType(.StaticText, identifier:"Please enter \"hoge\"")
    pleaseEnterHogeElementsQuery.childrenMatchingType(.TextField).element.tap()
        
    let moreNumbersKey = app/*@START_MENU_TOKEN@*/.keys["more, numbers"]/*[[".keyboards.keys[\"more, numbers\"]",".keys[\"more, numbers\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/
    moreNumbersKey.tap()
    app.typeText("123")
    pleaseEnterHogeElementsQuery.childrenMatchingType(.TextField).element
    app/*@START_MENU_TOKEN@*/.buttons["Done"]/*[[".keyboards.buttons[\"Done\"]",".buttons[\"Done\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap()
}

期待した通りに記録されない場合がありますが、
少し手を加えるだけで簡単にUIの確認をできそうです。

#テストしてみる
サンプルとして、以下のテストをしてみたいと思います。
・Login画面でテキストフィールドに正しくない文字列を入力し、Loginボタン押下
→アラート1が表示されることを確認。

・Login画面でテキストフィールドに何も入力せず、Loginボタン押下
→アラート2が表示されることを確認。

・Login画面でテキストフィールドに正しい文字列を入力し、Loginボタン押下
→Successful画面に遷移することを確認。遷移先(Successful画面)のbackボタン押下でLogin画面に戻ってくることを確認。

【Login画面】
Simulator Screen Shot 2016.08.20 3.55.00.png

【アラート1】
スクリーンショット 2016-08-20 4.01.12.png

【アラート2】
スクリーンショット 2016-08-20 4.01.01.png

【Successful画面】
Simulator Screen Shot 2016.08.20 3.55.51.png

テストコードは、記録後修正をして最終的に以下のようになりました。

SwiftUITestSampleUITests.swift
import XCTest

class SwiftUITestSampleUITests: XCTestCase {
        
    override func setUp() {
        super.setUp()
        
        // test Failure時にすぐ止める (trueにすると、test失敗しても最後まで処理する)
        continueAfterFailure = false
        
        // セットアップ毎にアプリを起動
        XCUIApplication().launch()

        // 画面の向きなどを指定したい場合はここで設定しておく
    }
    
    override func tearDown() {
        super.tearDown()
    }
    
    func testLoginFailedCaseMistype() {
        let app = XCUIApplication()
        let pleaseEnterHogeElementsQuery = app.otherElements.containingType(.StaticText, identifier:"Please enter \"hoge\"")
        let textField = pleaseEnterHogeElementsQuery.childrenMatchingType(.TextField).element
        
        textField.tap()
        app.typeText("typo")
        
        app.buttons["Done"].tap()
        
        app.buttons["Login"].tap()
        
        sleep(1)
        
        app.alerts["ログインエラー"].collectionViews.buttons["OK"].tap()
    }
    
    func testLoginFailedCaseNotInput() {
        let app = XCUIApplication()
        let pleaseEnterHogeElementsQuery = app.otherElements.containingType(.StaticText, identifier:"Please enter \"hoge\"")
        let textField = pleaseEnterHogeElementsQuery.childrenMatchingType(.TextField).element
        
        textField.tap()
        app.typeText("")
        
        app.buttons["Done"].tap()
        
        app.buttons["Login"].tap()
        
        sleep(1)
        
        app.alerts["ログインエラー"].collectionViews.buttons["OK"].tap()
    }
    
    func testLoginSuccessful() {
        
        let app = XCUIApplication()
        let pleaseEnterHogeElementsQuery = app.otherElements.containingType(.StaticText, identifier:"Please enter \"hoge\"")
        let textField = pleaseEnterHogeElementsQuery.childrenMatchingType(.TextField).element
        
        textField.tap()
        app.typeText("hoge")
        
        let doneButton = app.buttons["Done"]
        doneButton.tap()
        
        app.buttons["Login"].tap()
        
        sleep(1)
        
        app.buttons["back"].tap()
        
        let element = app.childrenMatchingType(.Window).elementBoundByIndex(0).childrenMatchingType(.Other).elementBoundByIndex(1).childrenMatchingType(.Other).element
        let textField2 = element.childrenMatchingType(.TextField).element
        textField2.tap()
        app.typeText("Misson complete!")
        doneButton.tap()
    }
    
}

画面内の文言を確認するために、要所要所に sleep(1)を入れてみました。

#さいごに
画面遷移や文言の確認を簡単にできるようになって便利です。

Recording機能だけでは期待する動作を再現するのがなかなか難しかったので、
テストコードの書き方について整理しました。
XCTest入門 (Swift) ~UITest編~ Part2

39
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?