20
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

Organization

XCTestでUITestするとき便利なもの、困ったこととその解決策

iOS10のリリースが間近に迫り、いろいろと新しいことにチャレンジする機会が増えそうです。iOS10がリリースされると、以下のような嬉しいことがあります。

  • iOS9以上でしか使用できないXCTestの活躍の場が増える

というわけで、ここ最近UITestのコードばっかり書いてたので情報整理したい

XCTestでUITestするやり方

1.accessibilityIdentifierを指定して一意にする
self.hogeButton.accessibilityIdentifier = "hogeButton";
2.viewのインデックスや、表示されている文字列から特定する
let tablesQuery = XCUIApplication().tables
tablesQuery.cells.staticTexts["ほげほげ"].tap()
tablesQuery.cells.elementBoundByIndex(0).tap()

1.が推奨だけど、テストしたい画面のviewにいちいち指定するのが大変。

また、UIRecordingで作られるのは主に2.のようなコード。

なので、基本的に2.でテストコードを書いてみて、viewを特定するのが難しかったら、1.でやってみることにした。

UITestするとき便利なもの

UIRecording

Gather Code Coverage をオンにする

  • オンにすると、Test Reportsが生成される
  • Test Reportsの目玉マークを押すと、テスト中のスナップショットが閲覧できる
  • テストに失敗したときどの処理で失敗したのか、とても見やすく見つけやすい
  • テストを重ねると、スクショが溜まって、ディスク容量がいっぱいになるので注意
  • やり方は下記のスライドの32ページからが1番わかりやすい

appium の inspector

  • これがあると、実機でテストしたい画面を表示させて、viewの要素を階層ごとに把握できる
  • セットアップや使い方は、下記の動画を見るのが1番楽だった
  • 一つ注意なのは、実機で inspector を表示するには下記が必要
    • brew install ideviceinstaller  

Xcode の Debug View Hierarchy

  • 公式ドキュメント - Examining the View Hierarchy
  • Debug View Hierarchyで表示できない画面はviewが多すぎて、viewの特定に時間がかかり、テストに失敗することが多い(たまに成功する)
  • Debug View Hierarchyで表示されない画面のUIテストは失敗率が高い(accessibilityIdentifierを指定しても)

先人の知恵

UITestするときに困ったことと、その解決策

cell や button をタップしてくれない時がある

  • Failed to scroll to visible (by AX action) ・・・の場合

  • Failure fetching attributes for element ・・・ の場合

    • Xcodeのデバックエリアで po XCUIApplication().tables.cells.elementBoundByIndex(0).buttons["ほげほげ"]とかすれば、対象のviewは一応特定できるがテストを実行すると失敗することが多い(たまーに成功するから厄介)
    • このエラーが出る画面では Debug View Hierarchy でおそらく表示できないので、viewが多すぎて XCUIElementQuery で探せないのが原因なのだと思う
    • 画面のUIを考え直すか、テストを諦めるか・・・

タップやスワイプなどのイベント動作が遅い

TextView や TextField にうまく文字が入力出来ない時

非同期処理などでviewが表示されるのを待ちたい

NSTimerなどのテストで遅延したい時

  • ストップウオッチがある画面などのUIをテストする時、一定の時間待ってからボタンをタップとかしたい
  • waitForExpectationsWithTimeoutdispatch_afterの組み合わせでやる
  • 例えば、開始ボタンを押すと、開始ボタンが一時停止ボタンになり、一時停止を押すと再開ボタンに変わる、みたいなストップウオッチ画面の場合
ストップウオッチのボタンの移り変わり
例「ストップウオッチのテストのために60秒遅延させる」

・・・

let app = XCUIApplication()
app.buttons["開始"].tap()

// ストップウオッチのテストのために60秒遅延
let timeout:Double = 60
let dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * Double(NSEC_PER_SEC)))
dispatch_after( dispatchTime, dispatch_get_main_queue(), {

    app.buttons["一時停止"].tap()
    app.buttons["完了"].tap()
});

// 再開ボタンが表示されるまで(一時停止が押されるまで)待って、後続の処理を遅延
let existsPredicate = NSPredicate(format: "exists == 1")
expectationForPredicate(existsPredicate, evaluatedWithObject: app.buttons["再開"], handler: nil)
waitForExpectationsWithTimeout(timeout + 3, handler: nil)

・・・

XCTestでUITestを書いてみて

  • 複雑な画面でなければ失敗することは少ない感じ
  • Debug View Hierarchyで表示できない画面は、UIを考えなおす必要がありそう
  • 初期コストはとても高いですが、一度書いてしまえば後がとても楽(それがテストというもの)
  • EarlGreyなどのOSSを使うと、人によっては初期コストが少し下がるかもしれません
  • appiumなら、クライアントもサーバーもテストが全てRubyとかJavaにできるので、お好みで
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
20
Help us understand the problem. What are the problem?