Help us understand the problem. What is going on with this article?

今こそgoogle/EarlGreyを使って自動UIテストに入門しよう

More than 3 years have passed since last update.

今年の2月にgoogleがiOS用自動UIフレームワークEaryGreyを公開してからおよそ10ヶ月が経ちました。EarlGreyは今現在も成長途中であるOSSではありますが、つい先日バージョン1.6.0がリリースされ、従来と比べて断然に導入が簡単になりました。
具体的には、以前のバージョンでは手動で各種Xcodeプロジェクト設定を行う必要があったのに対し、現在のバージョンでは各種ツールにより半自動で導入できるように改善されています。また、Swift 3にも正式対応1しました。

今回は、この最新版のEarlGreyの導入方法と簡単なUI自動テストの書き方について紹介したいと思います。

環境
- Xcode 8.2
- Swift 3.0.2
- iOS 10.2

事前準備

テストターゲットの追加とSchemeの設定

EarlGreyはUnitTestsターゲットを対象としてUI自動テストを実行します(UITestsターゲットではない点に注意)。
事前準備として、最初に「Editor -> Add Targets」と辿り、「iOS Unit Testing Bundle」を選択してユニットテストターゲットを追加しておきます。
次に「Product -> Scheme -> Manage Scheme」と辿り、「+」ボタンからユニットテストターゲット用Shcemeを追加して、「Shared」オプションにチェックを入れて下さい(もちろん、ユニットテストターゲットの追加については、プロジェクト新規作成時に「Inclue Unit Tests」にチェックを入れることで実現しても良いです)。
以下、EarlGreySwiftSampleAppがアプリターゲット、EarlGreySwiftSampleAppTestsがユニットテストターゲットとして話を進めます。

Qiita_EarlGreyAddUnitTestsTarget.png

Qiita_EarlGreyUnitTestsScheme.png

earlgrey gemのインストール

現在のEarlGreyはRubyGems化されたearlgrey gemと後で述べるCarthageを組みわせて使用することにより、半自動的にXcodeに導入できるようになっています。まずは下記の通り、Bundlerを使ってearlgrey gemをインストールしておきます。

Gemfile
source "https://rubygems.org"
gem "earlgrey"
Bundlerを使ってインストール
$ bundle install --path=vendor/bundle --binstubs=vendor/bin

XcodeプロジェクトへのEarlGreyの導入

Carhageと先ほどのearlgrey gemのコマンドを使って導入します。はじめにCarthageを実行します。

Cartfile.private
github "google/EarlGrey" "1.6.0"
Carhtageコマンドの実行
$ carthage update EarlGrey --platform ios

対象テストコードがObjective-Cベースである場合、ここまででEarlGreyの導入は完了です。

対象テストコードがSwiftベースである場合は、さらに以下を実行します。

earlgreyコマンドの実行
$ bundle exec earlgrey install --target=EarlGreySwiftSampleAppTests --swift_version=3.0

「target」オプションには対象となるユニットテストターゲット、「swift_version」オプションには使用するSwiftのバージョンを指定します。Swift 3系(3.0, 3.01, 3.0.2)を使用する際は3.0、Swift 2.3を使用する際は2.3を指定します。
EarlGreyは基本部分がObjective-Cで構成されており、このgemコマンドを実行することによりSwiftで必要となるラッパー用のファイルEarlGrey.swiftが追加されます。

テスト対象アプリの作成

ここでは、0以上の整数が入力されることを期待したageというTextField、およびそのことを確認するためのconfirmAgeというUIButtonを持ったサンプルアプリを対象とします。
※以下、EarlGreyの使い方を簡単に理解してもらうために、UI的に微妙だったり、冗長なコードだったりしていますが、ご容赦ください:-)

Qiita_EarlGreyStoryboard_640x480.png

アプリターゲットEarlGreySwiftSampleAppViewController.swiftにコードを追加します。コード中(1)でコメントしているように、後のEarlGreyテストコードでUIを特定するためにaccessibilityIdentifierを指定する必要があります。なお、この値については、Storyboardを表示させた状態で(Interface Builderから)、Identitiy Inspectorから設定してもOKです。

ViewController.swift(EarlGreySwiftSampleAppターゲット)
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var age: UITextField!
    @IBOutlet weak var confirmAge: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // (1) Needs to set accessibilityIdentifier for EarlGrey tests.
        self.age.accessibilityIdentifier = "ageTextField"
        self.confirmAge.accessibilityIdentifier = "confirmAgeButton"
    }

    @IBAction func confirmAge(_ sender: Any) {        
        if let age = Int(age.text!), age >= 0 {
            let alertController = UIAlertController(title: "Confirmed", message: "The age that you input is \(age).", preferredStyle: .alert)
            alertController.addAction(UIAlertAction(title: "OK", style: .default) { _ in })
            self.present(alertController, animated: true, completion: nil)
        } else {
            let alertController = UIAlertController(title: "Error", message: "Input an integer greater than or equal to 0.", preferredStyle: .alert)
            alertController.addAction(UIAlertAction(title: "OK", style: .default) { _ in })
            self.present(alertController, animated: true, completion: nil)
        }
    }

}

テストコードの追加

ユニットテストターゲットEarlGreySwiftSampleAppTestsEarlGreySwiftSampleAppTests.swiftにコードを追加します。grey_accessibilityIDによってaccessibilityIdentifierを指定していることに注目して下さい。

EarlGreySwiftSampleAppTests.swift(EarlGreySwiftSampleAppTestsターゲット)
import XCTest
import EarlGrey
@testable import EarlGreySwiftSampleApp

class EarlGreySwiftSampleAppTests: XCTestCase {

    override func setUp() {
        super.setUp()
    }

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

    func testConfirmAge() {

        var age = "foo"
        // Tests for strings
        EarlGrey.select(elementWithMatcher: grey_accessibilityID("ageTextField"))
            .perform(GREYActions.action(forTypeText: age))
        EarlGrey.select(elementWithMatcher: grey_accessibilityID("confirmAgeButton"))
            .perform(grey_tap())
        EarlGrey.select(elementWithMatcher: grey_text("Error"))
            .assert(with: grey_sufficientlyVisible())
        EarlGrey.select(elementWithMatcher: grey_text("OK"))
            .perform(grey_tap())

        age = "-123"
        // Tests for integers less than 0
        EarlGrey.select(elementWithMatcher: grey_accessibilityID("ageTextField"))
            .perform(grey_clearText())
            .perform(GREYActions.action(forTypeText: age))
        EarlGrey.select(elementWithMatcher: grey_accessibilityID("confirmAgeButton"))
            .perform(grey_tap())
        EarlGrey.select(elementWithMatcher: grey_text("Error"))
            .assert(with: grey_sufficientlyVisible())
        EarlGrey.select(elementWithMatcher: grey_text("OK"))
            .perform(grey_tap())

        age = "20"
        // Test for integers greater than or equal to 0
        EarlGrey.select(elementWithMatcher: grey_accessibilityID("ageTextField"))
            .perform(grey_clearText())
            .perform(GREYActions.action(forTypeText: age))
        EarlGrey.select(elementWithMatcher: grey_accessibilityID("confirmAgeButton"))
            .perform(grey_tap())
        EarlGrey.select(elementWithMatcher: grey_text("Confirmed"))
            .assert(with: grey_sufficientlyVisible())
        EarlGrey.select(elementWithMatcher: grey_text("OK"))
            .perform(grey_tap())
    }

}

自動UIテストの実行

通常のユニットテストと同様にCmd + Uにより、テストを実行します。上記コードの通り、入力フィールドに対して、文字列、負の整数、正の整数を順番にテストしてUI自動テストが実行される様子を確認できると思います。

最後に

いかがでしたでしょうか?もしかしたら、テストするためにそれなりに事前準備必要じゃねーか?と思っている方もいらっしゃるかもしれません!?...が、以前は様々なXcode設定を手動を行う必要がありました。大きな進歩です。また、そんなことはどういでもいいくらい、十分な価値があるフレームワークだと私は思っています。気になる点があれば積極的にぜひコントリビュートしていきましょう😉
なお、もちろん、EarlGreyだけで全てのUIテストがカバーできるわけではありません。要所要所で必要に応じて他のテストツールを組み合わせて効率よく素敵なアプリ開発を進めていきたいですね🎵


  1. 正確にはEarlGrey 1.4.0からSwift 3には対応していましたが、当時は別途Objective-Cブリッジングヘッダを追加する必要があったり、Swift 3っぽくない表記(Swift 2っぽい表記をひきずったまま)でした。 

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
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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