2020年はメルペイではBackend/Frontend/iOS/Androidの領域で、より素早いリリースイテレーションを達成するためにリグレッションテストの自動化が推進された年でした。これまでスプレッドシートなどで管理されていたテストの項目、実績管理などもTestRailというテスト管理サービスに移行させることでテストの自動化との親和性が上がりつつあります。私が持つiOSチームではリグレッションテストをXCUITestで自動化する取り組みをしていました。Bundleの構造や、情報の取り出し方について説明します。XCUITestを使ったUIテストの作成については弊社のエンジニアがiOSDCにて発表していますのでこちらのスライドや動画も是非ご覧ください。メルペイのUIテストの全体像メルペイでのUIテストの全体像について説明します。はじめに特定のラベルのついたPRへのPushや夜間にスケジュールされたトリガによってCircleCIのワークフローが起動します。次にワークフローの中でテストが実行され、その結果をTestRailに連携しています。管理などを行えるツールです。APIが提供されておりプログラムからTestRailの操作することも出来ます。メルペイではモバイルアプリのリグレッションテストについて手動・自動のいずれもTestRailで管理を行っています。https://www.gurock.com/testrail/docs/apiTestRailとの連携XCUITestの実行結果をTestRailに連携するためにメルペイではfastlaneのカスタムアクションを作成しています。APIを使って連携しています。Bundleについて詳しく知る必要があります。BundleをXcodeで開いて内容を確認してみましょう。Bundleである*.xcresultファイルが確認できます。$HOME/Library/Developer/Xcode/DerivedData/${プロジェクト名-xxx}/Logs/Testに生成されます。Bundleを出力して確認してみると良いでしょう。Bundleのフォーマットです。Bundleには以下のような情報が含まれています。ビルドログテストレポートテストカバレッジアタッチメントパッケージの中身はplistとバイナリファイルで構成されているため、テキストエディタなどで内容を照会することは出来ません。BundleはXcodeを使って内容を確認できます。xcresultファイルをダブルクリックして開いてみましょう。Navigatorタブのみ情報が表示されます。Bundleの内容を人が読むだけであればXcodeで開く方法で十分かもしれません。プログラムから結果を取り出したい場合には不向きです。そのような場合はxcresulttoolを使って情報を取り出します。xcresulttoolはAppleから提供されている、xcresultを人が読める、または機械的に解析が可能な形式に変換できるツールです。xcresulttoolで調べることができますが、本記事ではその内容に更にメルペイでの利用方法を例に添えて以下の4つのサブコマンドについて説明します。getformatDescriptionexportmergegetgetはxcresultの内容を出力するサブコマンドです。基本的にはこのコマンドを使ってxcresultからデータを取出します。以下の3つのオプションが用意されています。ないなどの不完全なものに対しては、バージョンを明示的に指定します。(指定しなければ最新のバージョンが使われます)以下のようにgetコマンドを実行するとxcresultのルートの階層の情報を得ることが出来ます。※出力結果は長いので一部省略してあります。{...}}getサブコマンドで得られた出力を理解するには次に説明するformatDescriptionサブコマンドで得られる情報からスキーマを理解する必要があります。Description)を得ることができます。データがどのような型や構造を持ってるかを確認することができます。formatDescriptionサブコマンドには更に2つのサブコマンドがあります。デフォルトで採用されます。Descriptionを内容を指定したフォーマットで出力します。Bundleが不完全な場合(Info.plistがないものなど)、バージョンを明示的に指定する必要があります--formatオプションでjson/text/markdownを指定した場合は定義されたオブジェクトの親タイプや種類(value/array/object)、プロパティなどの情報を得る事ができます。[String](#user-content-string)?...オブジェクトタイプについてオブジェクトのタイプは全部で58個あり、現状その全てのタイプの意味を調べきれてはいないので基本的なタイプについて抜粋して説明します。※--include-event-stream-typesオプションで更に追加で表示されるイベントストリームタイプを合わせると86個あります。タイプは大きく以下の3つに別れます。ValueArrayObjectValueには5つのプリミティブなタイプが用意されています。BoolDateDoubleIntStringArrayには1つのタイプのみ用意されています。ArrayObjectにはその他全てのタイプが該当します。タイプ名やプロパティを持ち、他のタイプに依存します。TestFailureIssueSummaryのようにスーパータイプにIssueSummaryを持つような継承関係にあるタイプも存在します。{...}},typeHierarchyオプションを指定すると継承関係がわかりやすく表示されます。TypeDefinitionReferenceタイプもxcresultを理解するために重要なタイプなので理解しておきましょう。xcresultのデータ構造は階層構造を持っており、各階層のデータはそれぞれObjectIDを持っています。getサブコマンドを実行する際--idオプションを指定しない場合はルートのオブジェクトIDが指定されます。ルートからさらに下層の情報を取得するには下層のオブジェクトのidを指定してgetサブコマンドで情報を取り出す必要があります。Referenceはそのidを持つオブジェクトです。以下はルートの階層からアクセスできるReferenceタイプのmetadataRefが持つ情報を出力したものです。{...}}...metaデータの具体的な情報を取得するためにはReferenceのidを指定してgetサブコマンドを実行します。Bundleのデータをどのように取出して利用しているか例を挙げて説明します。以下はあるテストについての実行結果をXcodeで開いたものと、TestRailにテスト結果として登録された内容です。TestRailにはテストの実行ログとしてこのような情報をテスト結果として送っています。テストが失敗した場合はこの実行ログを確認しどのような操作が行われたかTestRail上で確認できるようにしています。xcresulttoolを使って実行ログのはじめに出力されているTestRail-333513という文字列を取出す操作を例にとってみましょう。getサブコマンドを使ってActionsInvocationRecordオブジェクトを取得します。{...}}テストに関する情報はActionResultのtestRefのidを指定し更にgetを実行しActionTestPlanRunSummariesオブジェクトの情報を取出します。以下はその実行結果です。長いため必要な情報のみ抜粋しています。}}ActionTestPlanRunSummariesにはテストに関する情報が含まれていますがアクティビティの情報は含まれていません。アクティビティの情報を得るためには更にActionTestMetadataのsummaryRefのidで情報を取り出す必要があります。...}ActionTestSummaryのactivitySummariesからようやくTestRail-334452を取得することができました🎉subactivitiesプロパティは入れ子になっており、構造化されたアクティビティの情報が入っています。あとはこれを再起的に検索することでTestRailに送ったようなログを作ることができます。xcresulttoolを使ってjsonを生で見るのはなかなかしんどいものがあります、筆者としてはjqやfxを導入すると比較的この作業が楽になるのでオススメです。fxexportexportサブコマンドはファイルやディレクトリをxcresultから取り出すためのサブコマンドです。XCTAttachmentを使ったスクリーンショットなどの成果物を取り出すことができます。ないなどの不完全なものに対しては、バージョンを明示的に指定します。(指定しなければ最新のバージョンが使われます)例えば以下のように失敗したテストのAttachmentとして保存されているスクリーンショットの取り出しを例にexportコマンドの実行までを説明します。XCTAttachmentで保存したスクリーンショットはActionTestAttachmentのpayloadRefプロパティからObjectIDを取得する必要があります。getとformatDescriptionの具体例と同様にActionTestSummaryの情報を取得し、subactivitiesで階層を潜りつつ対象のアクティビティのattachmentsからpayloadRefのidを取得し、これをexportサブコマンドの--idオプションで使用します。APIを使ってテスト結果に添付するようにしています。Bundleを一つにマージすることができます。Bundleをマージするジョブを動かしています。Bundleを処理の対象として扱うためです。ワークフロー内では以下の5つのジョブが実行されます。BundleのマージXCTestHTMLReportの実行TestRailへの連携XCTestHTMLReportについては過去にメルカリエンジニアリングブログで取り上げたこちらの記事をご覧ください。Bundleのフォーマットxcresultとそれにアクセスするためのツールであるxcresulttoolの使い方を説明しました。実際にはxcresulttoolをそのまま使うのでは使い勝手が悪いのでfastlaneのカスタムアクションを作ってxcresulttoolの実行とjsonのパース処理を行っています。今後もiOSアプリ開発においてテストの実行結果を他のサービスとの連携する機会は増えるのではないかと思います。そのような時に本記事の紹介が一助になれば幸いです。メルペイではミッション・バリューに共感できるエンジニアを募集しています。一緒に働ける仲間をお待ちしております。引き続きお楽しみください。Appendixxcresulttoolのその他のコマンドについてご紹介します。diffdiffサブコマンドは二つのxcreultのフォーマットの差分を得ることが出来ます。以下はXcode11.6とXcode12.2にそれぞれ付属するxcresulttoolで得たformatDescriptionを比較した例です。このようにバージョンによって新たに追加されたタイプやプロパティなどの情報を確認できます。Bundleのオブジェクトグラフの出力を得ることができます。ないなどの不完全なものに対しては、バージョンを明示的に指定します。rawversionversionサブコマンドはxcresulttoolのバージョン情報を得ることが出来ます。