XCUITestを試す#1

# 概要

業務で開発中のiOSアプリケーションでUITest入れたいなーと思い触ってみました。
その備忘録です。

長いので分けて書いていきます。

今回はUITestの準備と簡単なテストについて書いていきます。

# テスト環境

Xcode: ver 11.1
Swift: ver 5.0

(2019/10/14に動作確認)

## なぜXCUITestなの？

Appiumじゃないの？と思う人もいるかもしれませんが
以前参加させてもらった[iOSTestNight](https://testnight.connpass.com)で

「XCUITestは公式がだしてるし安定しててよさげ」

みたいなことを聞いたのでXCUITestを触ることにしました。

# サンプル

このお話で実際試したサンプルこちらに置いときます。
https://github.com/rnishimu22001/UITestApplication

# 準備

すでに開発中のアプリに追加する予定なので
アプリ自体は用意してある前提で進めていきます。

## Target追加

Target を追加しましょう。
Xcodeの「File -> New -> Target」を選択してTargetを新規追加できます。

<img width="646" alt="スクリーンショット 2019-10-14 13.20.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161845/f369add9-18d6-6037-aebd-96d82ec6c4ed.png">


ここでUI Testingを選択

<img width="759" alt="スクリーンショット 2019-10-14 13.21.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161845/92ad365f-972a-0959-1ae8-2fc4980462cb.png">

Testのタブから先ほど追加したUITestの項目が追加されていたら準備完了です。

<img width="377" alt="スクリーンショット 2019-10-14 13.21.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161845/2e72b7f5-8fcc-4331-f9c3-e288abde7d0e.png">

# UITestを書く

UITestではアプリの各view要素は[XCUIElement](https://developer.apple.com/documentation/xctest/xcuielement)の単位になっています。
このXCUIElementに対して存在チェックや
タップなどの動作を行っていきます。

## 簡単なテストを試す

まずは簡単なテストを作っていきます。
以下のようなボタンが二つ並んだだけのアプリケーションを考えます。

<img width="100" alt="スクリーンショット 2017-07-23 16.08.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/161845/b2be4f9e-e170-27cf-5a3e-56b2af45bb53.png">

今回はボタンに対するテストをするので

まずは下準備としてアプリの起動とボタンの要素の取得について書いていきます。

### アプリを起動する

テストを実行する前にテストコード内でアプリを立ち上げる必要があります。
UITestのテストコード内からXCUIApplication().launch()で
テスト対象のアプリを起動できるのでsetUpなどで書いておきましょう。

```swift

class UITestApplicationUITopMenuTests: XCTestCase {
    let app = XCUIApplication()
        
    override func setUp() {
        super.setUp()
        self.continueAfterFailure = false
        self.app.launch()
    }
```

### ボタンの要素を取得する

基本的にテストではXCUIElementを取得して
このXCUIElementに対して存在チェックやいきます。

「buttonsのプロパティ + アクセシビリティID」で
UIButtonかつ指定したIDのボタンの要素を取得できます。

```swift
// XCUIElement
let button = XCUIApplication().buttons["設定したaccessibility ID"]
```

### Interface BuilderからAccessibility IDを設定する

Interface Builderから特定のViewに対してAccessibility IDを付与することができます。
右側のメニュー経由で設定できます。

<img width="703" alt="スクリーンショット 2019-10-14 13.36.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161845/b70f8169-2a89-fdd2-f777-c203a91f0f88.png">


###  ボタンに対してテストをする

ボタンに対してのテストと一口に言ってもいろいろありますが
今回は以下についてテストをしていきます。

* ボタンの要素が押せるか？
* ボタンの要素がアプリ上に存在しているか？(画面外も含む)
* ボタンの要素が画面上にあるか？
* ボタンの要素に表示されているテキスト正しいか？

#### ボタンの要素が押せるか？

この場合はisEnableを使います。
[(サンプル)](https://github.com/rnishimu22001/UITestApplication/blob/7efde70bcf2b5136d2c301aa9a627529aae057ca/UITestApplicationUITests/UITestApplicationTopMenuUITests.swift#L30
)

```swift
let button = XCUIApplication().buttons["TestIdentifier"]
XCTAssertTrue(button.isEnable)
```

#### ボタンの要素がアプリ上に存在しているか？

この場合はexistsを使います。
[(サンプル)](https://github.com/rnishimu22001/UITestApplication/blob/7efde70bcf2b5136d2c301aa9a627529aae057ca/UITestApplicationUITests/UITestApplicationTopMenuUITests.swift#L29
)

> This property determines if the element exists within the app's current UI hierarchy.

[公式からの引用](https://developer.apple.com/documentation/xctest/xcuielement/1500760-exists)

画面内の構成要素にあるかの判定なので見えない状態にしてある要素や画面外の要素でもtrueです。
とにかく「アプリ上にこの要素が存在しているか」をチェックしたい場合に使えます。

```swift
let button = XCUIApplication().buttons["TestIdentifier"]
XCTAssertTrue(button.exists)
```

#### ボタンの要素が画面上にあるか？

この場合はisHittableを使います。
[(サンプル)](https://github.com/rnishimu22001/UITestApplication/blob/7efde70bcf2b5136d2c301aa9a627529aae057ca/UITestApplicationUITests/UITestApplicationTopMenuUITests.swift#L32
)

> isHittable returns true if the element exists and can be clicked, tapped, or pressed at its current location. It returns false if the element does not exist, is offscreen, or is covered by another element.

[公式からの引用](https://developer.apple.com/documentation/xctest/xcuielement/1500561-ishittable)

テスト対象が別の要素の下にある場合や画面外にある場合はこのプロパティがfalseになります。

ScrollView上など画面には表示されてないが
アプリ上には要素がある場合などのチェックで使えます。

```swift
let button = XCUIApplication().buttons["TestIdentifier"]
XCTAssertTrue(button.isHittable)
```

#### ボタンの要素に表示されているテキスト正しいか？

この場合はXCUIElementのlabelのプロパティを使います。
[(サンプル)](https://github.com/rnishimu22001/UITestApplication/blob/7efde70bcf2b5136d2c301aa9a627529aae057ca/UITestApplicationUITests/UITestApplicationTopMenuUITests.swift#L34)

XCAssertEqualで表示されているテキストが
正しいかチェックしていきましょう。

```swift
let button = XCUIApplication().buttons["TestIdentifier"]
XCTAssertEqual(button.label, "Calc")
```

#### 最後に

UITestの要素に対する基本的なテストを書かせてもらいましたが
次回はTableViewに対するテストを書こうかなと思います。

#### 続き

続きを書きました！
[XCUITestを試す #2 (TableView編)](https://qiita.com/rnishimu22001/items/6781c316948c252377be)

#### 参考

https://developer.apple.com/documentation/xctest/user_interface_tests