[iOS]XCUITestを既存サンプルコードに適用してみた

別用もあって、XCUITestをちゃんと触ってみました。

XCUITestに対して多くのプロジェクトで問題になるのって、多分既存コードに組み込むことができるか?だと思うのですよね。(私もそうです)

なので、iOS6.0をdeploy targetにしているAppiumのサンプルコードを引っ張ってきて、それを7.0にあげた状態で動くか、というところから確認してみました。結果的に、アプリは7.0を保ちつつ、XCUITestはiOS9.0を対象にしてテストを回す、ということができました。Xcode8頃から怪しくなりそうな気がしているInstruments越しのUIAutomationを見ると、できるところからiOS9系だけでもXCUITestを視野に入れ始めたほうがよさそうですね。

修正したコードは以下に入れています。
git clone して、iOS9シミュレータをターゲットに設定して command + u で実行できます。

https://github.com/KazuCocoa/XCUITestExample/tree/master

やったことは、

  1. サンプルコードを取得する
  2. iOS7.0をミニマムにする
  3. XCUItestのターゲットを追加する
  4. 幾つかのテストコード書く(ついでに、accessibility付与したり、要素の結合したり)
  5. accessibilityIdentifiertitle、private methodへの切り出し

くらいです。

そのほか

Storyboardから、 accessibilityIdentifier を設定できるようになっていました。Storyboard中心になるのは、実装とUIを切り分けできているので良いのではないかなと思います。
ただ、動的に変化する要素に対してaccessibilityIdentifierを付与する、というのはやっぱりコード読み書き必要だし、テストコードはやっぱりSwift/Objective-Cになるだろうので、中身見ることができる人は必要、というのは変わらなくて良いのですけどね。

XCWaitCompletionHandler がwaitとしてつかえそうだったりと、Instruments越しのUIAutomationよりは、個人的に安定した並列実行とかもできるのでは?と少し期待。

これの成果物、Amazon Device Farmなんかにも適用できるかなー。



import XCTest
class TestAppUITests: XCTestCase {
private let app: XCUIApplication = XCUIApplication()
override func setUp() {
super.setUp()
continueAfterFailure = false
app.launch()
}
override func tearDown() {
super.tearDown()
}
func testShouldDisplayAlertWithText(){
app.buttons["show alert"]
.tap()
app.alerts["Cool title"].collectionViews.buttons["OK"]
.tap()
XCTAssertFalse(app.alerts["Cool title"].exists)
}
func testShouldDisplayAlertWithAccessibility() {
app.buttons.matchingIdentifier("accessibilityShowAlert").element
.tap()
app.alerts["Cool title"].collectionViews.buttons["OK"]
.tap()
XCTAssertFalse(app.alerts["Cool title"].exists)
}
func testShouldOpenGuesteView() {
app.buttons["Test Gesture"]
.tap()
app.childrenMatchingType(.Window).elementBoundByIndex(0).childrenMatchingType(.Other).element.childrenMatchingType(.Other).element.childrenMatchingType(.Other).element.childrenMatchingType(.Other).element.childrenMatchingType(.Map).element.tap()
XCTAssertNotNil(app.maps.matchingIdentifier("map view").element.exists, "don't display map view")
}
func testCulc() {
tap("IntegerA", ele_type: "text")
fillText("IntegerA", "1")
tap("IntegerB", ele_type: "text")
fillText("IntegerB", "1")
tap("ComputeSumButton", ele_type: "button")
XCTAssert(app.staticTexts["2"].exists)
}
private func tap(title: String, ele_type type : String){
switch type {
case "text":
app.textFields[title].tap()
case "button":
app.buttons[title].tap()
default:
app.textFields[title].tap()
}
}
private func fillText(title: String, _ body: String){
app.textFields[title].typeText(body)
}
}

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.