WebアプリをWebViewを使ったモバイルアプリにする「Capacitor」というライブラリがあります。Web制作の技術スタックでAppStore/Google Playで配信するモバイルアプリをつくれて便利なので、定期的に話題になるライブラリです。
Capacitorには、WebViewとデバイス上のネイティブコード(SwiftやJava)がやりとりをするためのプラグイン機構が搭載されています。これを使うことで、Webだけでは実現できない機能やユーザ体験を提供できるので、Capacitorを使って作られたアプリは大体はプラグインを利用しています。
プラグインは、Capacitorチームが提供しているコアプラグインだけでなく自作することもできますが、”作り方”は解説されていてもテストというか動作確認についてあまり話題にしている記事がないので、3つの方法についてみていきましょう。
3つの方法
アプリに組み込んでテストする
誰もがしている動作確認は、つくっているアプリに組み込んだ状態で行うテストでしょう。プラグイン開発後に、まずプラグインレポジトリで以下のコードを実行します。
% npm run build
% npm link
これにより、ビルド済みのパッケージを対象にシンボリックリンクが作成されます。
そのあと、アプリ側で以下を実行します。ここではつくったプラグインは capacitor-hoge
というパッケージ名だとしましょう( package.json
の name
フィールド)
% npm link capacitor-hoge
これでローカルでリンクされますので、 import { capacitorHoge } from 'capacitor-hoge'
のようにプロダクト内で使うことができるようになります。
ただアプリに組み込んでるので、Expect / Unexpect を両方手動で最後までテストしないといけなくなります。リリース前の最終確認段階は別ですが、日常的にはあまりやりたくないテスト方法ですよね。
プラグインにネイティブのテストを書く
プラグインは、Web / Swift / Javaでコードを書いてるわけですから、それぞれでテストコードを書けばいいんじゃない?という、とても正しいテストへの向き合い方です。例えば、 @capacitor-community/admob
では、Bannerの表示に関わるテストは以下のようにテストを書いています。
ただ留意が必要なのは、これは1プラットフォームでの動作を担保するテストであり、プラットフォームごとのテストが必要になります。また、ほとんどのプラグインが「ネイティブライブラリのラッパー」であることを考えると、ライブラリのテストをプラグインで実行するのにほぼ等しくなるので、コストほどのリターンを得ることは難しいでしょう。
例えば、
@capacitor-community/admob
は、AdMobライブラリをWebViewから実行できるようにしてるラッパーライブラリであり、独自機能を持たないのでこれに該当します。けれど、Modalを立ち上げてプロダクトのネイティブコードと統合するようなプラグインの場合はこの限りではありません
そう思うと、ネイティブレベルで行うべきは機能のテストより手前のビルドテストで十分なことがほとんどでしょう。Capacitorプラグインのテンプレートには最初から以下のコードが用意されているので、これをGitHubのCIで通せば最低限の確認はできます。
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
"verify:android": "cd android && ./gradlew clean build test && cd ..",
"verify:web": "npm run build"
テストを半自動で実行するデモプロジェクトの作成
まずはこれをみてください。私はCapacitorプラグインは基本的にこのような自動実行のデモプロジェクトを用意するようにしています。
これはタブを切り替えたイベントで発火して、メソッドを順に実行しながら、期待した結果とイベントを取得するようにしています。この最も優れた点は、
- プラグインのメソッドの使い方が実装コードレベルでわかる
- 結果やイベントの値が、デバイスで異なる場合は検知できる
という2点です。まず1つめは自明ですよね。使い方聞かれた時に、「デモコードみておいて」といえるのはとても便利です。そして2つ目は、「iOSとAndroidで実装者が異なって返ってくる値が間違っていても、デモプロジェクトの実行段階で気付ける」というメリットがあります。いや、本当ひとりでプラグイン開発していても、iOSでは返り値の最初の文字が大文字なのに、Androidでは小文字だったり。そもそもイベント発火のタイミングが異なってたり。これをつくるまではこういう小さなミスに本当悩まされました。それがこれだけで解決!
プラグインと開発者の特性にあわせて組み合わせよう
今のところ、私が開発しているプラグインは、この3つを組み合わせてテストするようにしています。個別的に「iOSのverifyが遅すぎる。GitHub Actionsの時間食い尽くすからこのテストはコメントアウトしよう」みたいなのはあったりはしますが、CIに組み込める「プラグインにネイティブのテストを書く」はプルリクエストをレビューする時には必須ですし、デモプロジェクトがないと開発者体験の落ちるプラグインになってしまいがちです。また、最終の組み込みテストはどちらにしても必須ですよね。
テストの必要性はわざわざ語るまでもないですが、できるだけ日常のプラグインメンテナンスのコストを下げるために、どこまで自動化できるか、また自動化しすぎたらテストメンテナンスのコストが大きくなるのでどうやってバランスをとるかを考えると、よりよいテストがみえてくるかと思います。
それではまた。