LoginSignup
6
4

More than 5 years have passed since last update.

EarlGrey2を触ってみた

Last updated at Posted at 2018-10-27

iOSのUIテストを支援するGoogle謹製ライブラリEarlGreyのバージョン2.0が2018年10月2日に公開されました。まだベータ段階ですが一通り動くようなので、概要やインストール方法などを解説します。

EarlGrey1系について

EarlGrey1系はざっくり言うとXCTest上で動作するUIテスト支援ライブラリです。(XCUITest上ではない)

なぜそんなものが必要なのか。
Xcodeの標準UIテストであるXCUITestはテスト対象のアプリを外側から操作するコードを書くことができるフレームワークです。
このためXCUITestで書いたテストコードは別アプリとして開発端末にインストールされます。
別アプリなので本体アプリ側のUserDefaultsの状態を変更するといった、テストの前提条件を整える処理をテストコードとして書くことができません。
できることはアプリのUIを介した操作だけです。
このことをEarlGreyでは、XCUITestはブラックボックステストだ、と表現しています。

これだとテストの自由度が低すぎますよね。
これを解消するためにEarlGrey1系では、本体アプリ側の処理ができるXCTest上でUI操作やUI要素のアサーションができるライブラリを提供していました。

イメージとしては以下の図のような関係性です。

EarlGrey1.png

EarlGrey2.0へ

素晴らしいEarlGrey1系ですが、いくつか解決が困難な課題を持っていました。
例えばiOSのシステムが表示するパーミッションダイアログを操作できなかったりします。
前もってパーミッションの操作をしておくとか運用で逃げることはできる(はず)ですが、あまりイケてないですよね。

そこでEarlGrey2.0では考え方をガラリと変えました。
XCTestで限界があるならば、XCUITestをホワイトボックス化すればいいじゃないか!と方針変更したのです。

ホワイトボックス化をどのように実現しているか。
HelperBundleというターゲットを別途用意し、これを通して本体アプリ側の処理をするアプローチを取っています。

関係性はこんな感じになります。

EarlGrey2.png

導入手順

ベータのためCocoapodsやCarthageにはまだ対応していません。(次の四半期でやるよ!って書いてあります)
このためインストールは普通よりも手順が多いです。
またホワイトボックス化の重要な要素であるHelperBundleは個別に用意する必要があるため、パッケージ管理では対応できないんじゃないかなーと思ってたりします。
ほぼ公式マニュアルの日本語訳ですが、誰かの助けになれば幸いです。

以下、例ではEarlGrey2を導入するプロジェクトの名前をWorkEarlGrey2として説明します。

EarlGrey2のインストール

  1. EarlGrey2をダウンロード
    git clone --recursive -b earlgrey2 https://github.com/google/EarlGrey.git を実行。
    --recursive をつけることで、HelperBundleを動かすキーとなる eDistantObject ライブラリが一緒に落ちてくるので、このままコピペすることをおすすめします。

  2. EarlGrey2をXcodeプロジェクトに取り込み
    EarlGreyを導入したいXcodeのプロジェクトを開いて、ワークスペースに EarlGrey.xcodeproj ファイルをドラッグ&ドロップします。
    必ずプロジェクト内にドロップしてください。外側に配置されてしまうと別のワークスペースになってしまいます。
    workspace.png

  3. EarlGreyのライブラリがビルドできるか確認
    うまく取り込めていればXcode左上のビルドターゲットにEarlGreyのライブラリが追加されています。
    ここで一度ビルドターゲットを変更して、 TestLibAppFramework がビルドできるか確認しておきます。

XCUITestの設定変更

XCUITestターゲットの設定を変更して、EarlGreyが動くようにします。

  1. Build Phases - Link Binary with Libraries で libTestLib.a を追加
    testlib.png

  2. Build Settings - Other Linker Flags に -ObjC を追加
    linkerObjC.png

  3. Build Settings - User Header Search Paths に EarlGrey.xcodeprojeDistantObject.xcodeproj があるディレクトリを追加
    userHeaderSearchPaths.png
    プロジェクトルートからの相対パスで記述できます。例ではプロジェクトルート直下にEarlGreyを落としてきています。

  4. Build Phases に 新しい Copy Files Phase を追加

    1. 左上の+ボタンを押して、 New Copy Files Phase を選択
    2. 追加した Copy Files Phase に以下を設定
      • Destination: Absolute Path
      • Path: $(TARGET_BUILD_DIR)/../../<YOUR_APPLICATION_TARGET_NAME.app>/Frameworks
      • Copy only when installing のチェックは外す
      • 下の方にある+ボタンを押して AppFramework.framework をコピー対象に追加。 Code Sign On Copy にチェックをする。 copyAppFramework.png
  5. Swiftでの設定
    Swiftプロジェクトの場合はいくつか追加の手順が必要になります。

  6. XCUITestをビルドして確認
    ここまでがいったんXCUITestへのEarlGreyインストール手順となります。
    EarlGrey1系で使っていたUI操作の処理などはこの時点で可能です。
    テストコードがビルドできるか確認しておきましょう。

HelperBundle の作成

ここからがEarlGrey2.0の肝になるHelperBundleの作成です。

  1. HelperBundleターゲットを追加

    1. Xcodeのメニューから File >> New >> Target を選択
    2. macOS のタブを選択
    3. Bundle を選んで Next addHelperBundleTarget.png
    4. 名前などは適当につける(例では EarlGreyHelperBundle とした)
  2. HelperBundleターゲット の Build Settings を以下のように設定

    • Base SDK: Latest iOS
    • Other Linker Flags: -ObjC を追加
    • Bundle Loader: $(TARGET_BUILD_DIR)/<YOUR_APPLICATION_TARGET_NAME.app>/<YOUR_APPLICATION_TARGET_NAME> を設定 helperbundlebundleloader.png
    • User Header Search Paths: EarlGrey.xcodeprojeDistantObject.xcodeproj があるディレクトリを追加 helperbundleheadersearchpaths.png
    • (Swiftのみ)RunPath Search Paths: @loader_path/Frameworks を設定
    • Always Embed Swift Standard Libraries: Yes
      • ※公式マニュアルに記載がないが、サンプルプロジェクトで記載されていたため設定。設定しないとテスト実行時にクラッシュする。
    • Enable Bitcode: No
      • ※公式マニュアルに記載がないが、サンプルプロジェクトで記載されていたため設定。設定しなくても問題発生しないが念の為。
  3. HelperBundleターゲット の Build Phases を以下のように設定

    • Target Dependencies に アプリ本体 を追加
    • Link Binary With Libraries に AppFramework.framework を追加し、 Statusを Optional に設定 helperbunldebuildphases.png
  4. XCUITestターゲットの Build Phases で HelperBundle をアプリに組み込む

    1. XCUITestターゲットの Build Phase に移動
    2. 左上の+ボタンを押して、 New Copy Files Phase を選択
    3. 追加した Copy Files Phase に以下を設定
      • Destination: Absolute Path
      • Path: $(TARGET_BUILD_DIR)/../../<YOUR_APPLICATION_TARGET_NAME.app>/EarlGreyHelperBundles
        • 必ず EarlGreyHelperBundles ディレクトリを指定する必要がある。EarlGreyはここを決め打ちで見に行く模様。
      • Copy only when installing のチェックは外す
      • 下の方にある+ボタンを押して <YOUR_HELPER_BUNDLE.bundle> をコピー対象に追加。 Code Sign On Copy にチェックをする。 helperbundleselect.png helperbundlecopy.png
  5. Bridging-Header を設定
    Swiftの場合はHelperBundleでもBridging-Headerが必要となる。
    設定方法はXCUITestの設定で記載したものと同じ。
    設定内容は以下の通り。(TestLib関連はimportしない)

#import "AppFramework/Action/GREYAction.h"
#import "AppFramework/Action/GREYActionBlock.h"
#import "AppFramework/Action/GREYActions.h"
#import "AppFramework/Matcher/GREYElementMatcherBlock.h"
#import "CommonLib/DistantObject/GREYHostApplicationDistantObject.h"
#import "CommonLib/Matcher/GREYMatcher.h"

HelperBundleを使って、アプリ本体の処理を動かす

これでようやく設定周りは完了で、テストコードに取り掛かれます。
以下のファイルをHelperBundle内に新規作成します。

  • SwiftTestsHost.swift
    • XCUITestに公開するプロトコル
    • HelperBundleとXCUITestの両方に追加する
SwiftTestsHost.swift
@objc
protocol SwiftTestsHost {
  /// Obtain the host application's interface orientation.
  func interfaceOrientation() -> UIInterfaceOrientation
}
  • GREYHostApplicationDistantObject+SwiftTestsHost.swift
    • アプリケーション側の処理を記述する
GREYHostApplicationDistantObject+SwiftTestsHost.swift
extension GREYHostApplicationDistantObject: SwiftTestsHost {
  func interfaceOrientation() -> UIInterfaceOrientation {
    return UIApplication.shared.statusBarOrientation
  }
}

次に、XCTestCaseクラスを拡張します。hostコンピューティッドプロパティをextensionで生やして、SwiftTestsHostで定義されているファンクションを呼び出せるようにします。
書く場所はどこでもいいです。例ではデフォルトで追加されるテストケースファイル内に記述しています。

WorkEarlGrey2UITests.swift
extension XCTestCase {
    /// A variable to point to the GREYHostApplicationDistantObject since casts in Swift fail on
    /// proxy types. Hence we have to perform an unsafeBitCast.
    var host: SwiftTestsHost {
        return unsafeBitCast(
            GREYHostApplicationDistantObject.sharedInstance,
            to: SwiftTestsHost.self)
    }
}
// 以下、省略

これで準備完了。アプリケーション側の処理を動かしてみましょう。

WorkEarlGrey2UITests.swift
class WorkEarlGrey2UITests: XCTestCase {
    func testInterfaceOrientation() {
        continueAfterFailure = false
        XCUIApplication().launch()

        // XCUIApplication().launch() の後に
        XCTAssertEqual(host.interfaceOrientation(), UIInterfaceOrientation.portrait)
    }
}

サンプルプロジェクト

EarlGrey2.0内にサンプルプロジェクトが同梱されています。
EarlGrey/Tests/FunctionalTests

サンプルとしてきちんとUIテストの実行まで動作するので信頼できます。
インストールするのもマニュアルだけだと辛かったので、この設定と見比べたりして解読しました。

サンプルプロジェクトの構成

Objective-C版もSwift版も両方入っているのですが、私がSwiftをメインで使っているのでSwift版として説明します。(Swiftを取れば、Objective-C版になると思います。多分。)

  • FunctionalTestRigSwift
    • テスト対象となるアプリです。
  • FunctionalSwiftTests
    • UIテストターゲットです。
  • HostDOCategoriesSwift
    • HelperBundleです。

まとめ

EarlGrey2.0ではXCUITestベースに移行したため、レコーディング機能が使えたり、UI操作やアサーションをXCUITestのスタイルで記述することもできます。
その上で本体アプリ側の処理をすることもできるようになり、XCUITestの弱点が見事に補われています。

XCUITestの限界を感じたら、ぜひ試してみてください。

6
4
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
6
4