こんにちは、第二事業部でエンジニアをしている渡邊です。普段はiOSアプリの開発プロジェクトを担当しています。今回はiOSアプリケーションのテストについてお話ししていきます。
はじめに
これまで私はいくつかのiOSアプリ開発、保守案件を担当しましたが、テストの導⼊にはほぼ関わったことがありませんでした。しかし、先日担当したWebアプリケーションの保守案件で、少しですがテストコードに触れる機会がありました。そのときに感じたメリットを以下にご紹介します。
- 結合テスト時に報告される不具合が⽐較的少ない
- 安⼼して改修、リファクタリングができる
- コードが疎結合になる
普段関わることの多いiOSアプリ開発でも、このような効果が⾒込めるのでは?と思いました。そこで、今回は実際のアプリにUITestを導⼊し、通常の実装に加えてどの程度の⼿間がかかりそうか、また実案件に導⼊できそうかを検討してみます。
UITest導入対象アプリについて
概要
SwiftUIを使用してiOSアプリにUITestを導入した方法について紹介します。
対象者
iOSアプリのUITest導⼊に興味のある⽅
実行環境
- Xcode 15.1
- Swift 5.8.1
- フレームワーク SwiftUI
今回使⽤するアプリは、飲⾷店検索アプリです。飲⾷店のデータはHOTPEPPERグルメAPIを利⽤しています。(画像では店名等が表示されないように処理しています)UIは以下の画像のようになっています。各画⾯の仕様は、後のテストコードでわかる内容になっているため省略します。
GUIアーキテクチャは MVVM を採用しています。
UITestの導入
ここからはUITestのコード実装について、画⾯ごとに説明していきます。
主に画⾯のテストでは、初期状態とタップイベントの検証を⾏いました。 全体的なテストケースのコードの流れは、以下のようになっています。
- アプリ起動
- 検証対象画⾯の要素取得
- タップイベント等があった時にイベント発⽕
- 画⾯要素の状態を検証
また、テストコードファイル以外に本体コードへの修正が必要です。「2. 検証対象画⾯の要素取得」は画⾯要素のIDを指定して取得しているので、本体コードであらかじめ指定しておく必要があります。実際には以下の通りです。
IDはString型の値を指定すれば良いのですが、あつかいやすく Enum として画⾯ごとに定義しています。
検索結果画面
基本的には検索画⾯と同様です。この画⾯の場合、初期表⽰として検索結果有り・無しの2パターンの検証を⾏う必要があります。そのため launchArguments を利⽤して、以下のようにMockを差し替えています。
⾃前で定義したViewを使っているため、画⾯要素の取得に関して注意点があります。⾃前で定義したViewでは、 otherElements を指定すると共に、id指定時に accessibilityElements() を指定する必要があります。
飲⾷店詳細画⾯
こちらもこれまでと同様です。この画⾯では、Listで共通化したセルを表⽰していますが、セルには同じidが指定されています。そのため⼀旦それぞれのセルを取得し、さらにidを指定してセル内のテキストなどを取得しています。
さいごに
実際にiOSアプリへのUITest導⼊をやってみて、ハードルはそこまで高くないと感じました。 難点をあげると、本体コードにテストコードのための実装が⼊ってしまうことです。UITestを導⼊する上で、これは避けられない点かもしれません。
IDの指定⽅法が統⼀されていないと、かなりあつかいにくいコードになる可能性があります。事前にルールを決めて、チーム内で共有しておくべきでしょう。また、画⾯のパターンを複数検証するためには設計⾯でも考慮が必要です。MVVMなどを利⽤して、画⾯とプレゼンテーションロジック、状態管理を切り離す等のルールを統⼀しておくことで、テスタビリティだけでなく保守性も向上します。
UITest導⼊をまとめると、個⼈的には以下の2つがポイントになると思いました。
- ID 指定ルールを明らかにする
- 画⾯データを切り替えやすい状態にする
上記の2つを意識すれば、実案件への導⼊も難しくないと感じます。実案件ではより複雑な画⾯になり、課題も増えると思いますので、機会があればiOSアプリ開発の現場で試してみたいです。