Firestoreのrulesのテストを全てローカルエミュレータを使うように書き換えた話Komerco事業部エンジニアの岸本(id:sgrksmt)です。Databaseにローカルエミュレータがβ版として追加されたという発表がありました。全てローカルエミュレータを用いたrulesのテストに書き換えました。今回はローカルエミュレータを用いたFirestoreのrulesのテストの話をします。使うと何が変わるかローカルエミュレータを使ったrulesのテストに切り替えることによって、良い点がいくつかでてきます。テストを実行するためのfirebaseプロジェクトを別途用意する必要がなくなるfirebaseプロジェクトにrulesをデプロイしてからテストする必要がなくなるオンラインテストと比べてテストの所要時間が短くなる開発環境のバッティングによってテストが壊れることがなくなる特にテストの時間が短くなることと、開発環境のバッティングによってテストが壊れることがなくなるのは大きいです。CIで用いるfirebaseプロジェクトは1つなのでCIの走るタイミングによってはrulesが違うものに変わってしまいテストが通らない...なんてこともありました。ローカルエミュレータを使うことでそれらの問題から解放され、デプロイ前に手元でテストができるようになります。変更前と後を図で示すとこのようになります。BeforeAfterまた、テストの所要時間ですが変更前後でこのように変わりました。(各5回ずつ実行の平均値を取っています。)テストケースはおよそ60ケースほどです。約13秒テストケースの大きさ、複雑度によって変わりますが、1/3ほどに減らせたのはとても大きい改善となりました。実際に使ってみる実際にFirestoreのローカルエミュレータを使ったテストを書くところまで説明していきます。公式のドキュメントはこちらにもあるのですが、細かく解説していきます。※なお、この記事の投稿時点ではβの機能となっています。事前準備toolsの更新とemulatorのインストールまず最初に、firebase-toolsのバージョンは6.0.0以上である必要があります。"^6.0.0",}のように記述し、firebase-toolsをインストールあるいはアップデートします。その後、emulatorの準備をします。し直すのは不要かと思います。実行し、プロセスが起動してlocalhost:8000が立ち上がるのを確認します。実行すると、firestore-debug.logが吐き出されるので、不要ならignoreします。.gitignorefirestore-debug.logfirebase/testingの追加package.jsonにfirebase/testingを追加し、インストールをします。}ここまで問題なければ事前準備は終了です。firebase/testingfirebase/testingモジュールを使うことで、firestoreの読み書きのテストを書くことができるようになります。テストを書くのに使用するインターフェースを紐解いていきます。projectIDについてfirebase/testingを使ってテスト用のFirebaseのAppを作成します。その時にprojectIDを指定して作成するのですが、このIDはテストケース毎に一意である必要があります。Appを立ててアクセスしてしまうと、他のテストケースで作成したデータが混じっていてテスト結果に影響を及ぼす可能性があります。projectIDを作成するときはタイムスタンプや乱数を含めて一意にすると良さそうです。公式のサンプルでは次のようにprojectIDを作っています。}}テストケース毎に、firestore-emulator-example-[テスト開始時のタイムスタンプ]-[テスト番号]という文字列でprojectIDを生成しています。testNumberはbefore(Each)が実行されるときにインクリメントしています。このように一意となるprojectIDを生成すれば、テスト時に問題になることはないでしょう。rulesファイルをロードするエミュレータにprojectIDを指定してrulesを読み込ませます。先のコードの例にもありましたが、このようにしてrulesの内容を文字列として渡してあげます。rules})今後はこのprojectIDと一致するFirebaseのAppを作成することで、そのAppはここでロードしたrulesを見るようになります。}}).firestore()引数にはprojectIDと、auth情報を渡します。App(Firestore)を用意できる点です。今までのrulesのテストの場合、認証ユーザーを切り替えながらデータを作成するときは次のように一々signInとsignOutを繰り返していました。})このように書くことができます。signInしたりsignOutしたりがなくなるので見通しがよくなりますし、「userAで作成したドキュメントのpathを基に、userBでは書き込みができない」、といったテストを以前より簡単に書くことができるようになります。パラメータにnullを渡します。null}).firestore()これで認証の通っていないユーザーに対するテストもかけるようになります。admin権限でFirebaseのAppを作成するテストを書くときに、事前にFirestoreにテストデータを入れたい場合があります。このときに、rulesの影響を受けずにデータを作成したり、作成したデータを読み出したい場合には、admin権限でFirebaseのAppを作って利用します。Appを削除する必要があります。app.delete()))これらの処理をclassにまとめてモジュール化rulesファイルのロードから、各テスト実行ごとに一意のProjectIDを作成してAppを作ってfirestoreを利用する処理を、classとしてまとめてimportできるようにすると便利になります。KomercoではFirestoreTestProviderというクラスを作り、各テストファイルでimportしています。}}エミュレートしているfirestoreへの書き込みの成功失敗を評価する書き込みが成功する/失敗するのを評価する場合は、assertSucceeds、assertFailsを使います。firebase.assertSucceeds(db.collection('users').doc('user').get())ちなみに、assertSucceeds、assertFailsの実装はこちらで確認ができます。Succeedsは単純にpromiseを返し、failsの場合はPromiseが成功したらエラーを返し、失敗したらエラーを値として返すようにしています。(成功と失敗を反転させている)これは使っても使わなくても問題ありません。(jestの場合はexpectで評価することもできますし。)テストを書く先程のFirestoreTestProviderと、テストフレームワークであるjestを使ってテストを実際に書いてみます。quickstartと同じもので組んでみました。実行してエミュレータを起動した上で、jestを実行するとテストが動きます。サンプルはこちらにあります。最後にローカルエミュレータは投稿時点ではβ版ということですが、とても強力かつ手軽に扱えるのでこれからテスト書こうかなとか、以前僕が書いた記事のようにテスト書いてる場合は是非検討してみてはいかがでしょうか。ローカルエミュレータ以外にも様々な発表があったので、キャッチアップしていきながら導入や実践できそうなものがあればどんどんKomercoで試していこうと思います。MessagingのUIをカスタマイズして運用するKomerco事業部エンジニアの岸本(@_sgr_ksmt)です。F...2019-07-05Firebaseで運用するKomercoの管理用アプリケーションの開発こんにちは。sgrksmt)です。コメルコテックバナシ〜新規事業開発のリ...こんにちは。id:tokunarigyozada...2018-07-17Firebaseを活用したiOSアプリ開発事例こんにちは。新規サービス開発部の中村です。使ったセキュリティログ検索基盤の構築サービス特性にあった検索システムの設計戦略クックパッド採用説明会「クックパッドはサービスの作り手を採用したいんです。/*}*/スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。