見出し画像

Autifyテストシナリオを作りやすくする認証基盤

こんにちは。Tably よういちろう です。寒くなってきて、最近では鍋を欲する日が多くなってきました。肉、魚、野菜、その組み合わせは無限です。素敵な季節だな、と思っています。

さて、以前「Autifyをより活用するためのポイント」という記事を公開させていただきました。その記事の中では、「テストシナリオをできるだけ小さく作る」ことを推奨させていただきました。

テストシナリオを細かく作っていく、という一見簡単なことのように思えるこの工夫ですが、テストシナリオを「メンテナンス性良く」「安全に」「低コストで」作っていくためには、更にいくつかの細かな工夫が必要になります。その工夫は、Autify の機能を使いこなすこと以外にも、Autify のテスト対象となるサービス側に工夫を入れることで、劇的に「メンテナンス性良く」「安全に」「低コストで」テストシナリオを作っていけるようになります

このエントリでは、そんな工夫の中の一つである「認証基盤」について、紹介したいと思います。

メンテナンス性良く、安全に、低コストで

今回の話の始めとして、目指すべき「メンテナンス性良く」「安全に」「低コストで」とは、実際にはどんな状態なのかを整理してみます。

1つ目の「メンテナンス性良く」は作成したテストシナリオに対して、仕様変更時にもテストシナリオの修正箇所が明確であり、捨てて作り直しても痛くないという状態を維持することです。これがメンテナンス性の向上の鍵となります。詳しくは「Autifyをより活用するためのポイント」で紹介した「テストシナリオが細かく作られている状態」をご覧ください

メンテナンス性が良い状況を保ったままテストシナリオを作成していくと、その副作用として、テストシナリオの数が多くなってきます。Autify では、複数のテストシナリオを同時に実行することが可能ですので、数が多くなったとしても、その並列実行のおかげで、全てのテストシナリオの実行完了時間の短縮を見込むことができます。

しかし、これは、「いつどのテストシナリオが同時に実行されるかわからない」という状況となることを意味しています。

2つ目の「安全に」とは、いつどのテストシナリオが同時に実行されたとしても、個々のテストシナリオが正しく実行されることを意味しています。

画像1

3つ目の「低コストで」は、「安全に」テストシナリオを作成していく際に、個々のテストシナリオが他のテストシナリオに影響しないことを「できるだけ何も考えずに」保証することができている状態のことを指します。テストシナリオを作っていく際に、絶えず「これをやったら他のテストシナリオに何か起きそうだな」と気にしていては、テストシナリオを作っていくモチベーションはどんどんと下がっていってしまいます。

画像2

まとめると、「メンテナンス性良く」「安全に」「低コストで」という状況は、

「特に気にすることなく数多くの細かなテストシナリオが複数同時にいつ実行されたとしても問題がない」

という状況と言い換えることができます。

あるテストシナリオが別のテストシナリオの実行に影響を及ぼしてしまう原因は、主に「Race condition(競合状態)」です。

例えば、データベースに格納された情報の変化を考えてみましょう。データベース内の「A」という情報がテストシナリオ 1 により「B」と変更されたとします。テストシナリオ 1 としては「B」になったことは正常とみなしていますが、テストシナリオ 2 では「A であることを前提に○○が行われて C になる」ということが期待されていたとすると、その前提条件が崩れます。結果として、テストシナリオ 2 は期待した挙動ではなくなり、アサーションに失敗してしまうことでしょう。

画像3

もちろん、Autify には「並列実行」だけでなく「逐次実行(一つずつ順番に実行する)」のオプションがあります。これを使えば、Race condition の発生を回避することが可能です。しかし、これには「テストシナリオの実行順を厳格に管理しなければならない」ことと「並列度の低下による総実行完了時間の増加」という別の問題が発生します。

画像4

つまり、並列実行のメリットを活かしつつ、Race condition を発生させないための方法があれば良さそうです。最もシンプルな方法とは何か、それは、

「複数のテストシナリオで同じ情報を一切使わない」

ということです。個々のテストシナリオが全く別の情報を使うことで互いに「隔離」されていれば、テストシナリオが別のテストシナリオといつ同時に実行されようとも影響を与える心配はなくなり、結果として何も気にすることなく「低コストで」テストシナリオを「メンテナンス性良く」作成していくことができ、そして「安全に」なります。

ユーザ認証を使って情報を「隔離」する

テストシナリオごとに情報を隔離するための方法は、アプリ/サービスによって異なりますが、ここでは「Autifyをより活用するためのポイント」で取り上げた Moderator というサービスを例として上げます。

Moderator は、イベントや社内会議などで、質疑応答やアンケートをとることを簡単に行うためのウェブサービスです。Moderator のユーザは、「イベント管理者」と「イベント参加者」という 2 種類が存在しています。そして、イベント管理者向け機能と、イベント参加者向け機能とで、明確に分かれています。

画像5

Moderator のユースケースは、「イベント管理者がイベントを作成し、質疑応答セッションやアンケートセッションを作成する」「イベント参加者が対象のイベントに対して、質問を投稿したり、アンケートに回答する」という流れとなります。

イベント管理者向けの機能群は、認証された Google アカウントごとに提供されます。そして、イベント管理者 A さんが作ったイベントは、他のイベント管理者からは基本的に見えません。つまり Moderator では、イベントの情報はログインユーザごとに「隔離」されていることになります。

画像6

次にイベント参加者についてですが、これは Firebase Authentication の匿名ユーザ認証の仕組みを使って実現しています。つまり、Chrome であれば、ユーザプロファイルが違えば、Moderator からは「別のイベント参加者」として識別されます。イベント管理者と同じように、イベント参加者もユーザプロファイルが違えば「隔離」されます。

これらのことからわかる通り、Moderator にて情報を隔離するための最もシンプルな方法は、「テストシナリオごとに異なるログインユーザを使用する」です。

画像7

Autify では、一つのテストシナリオに対して、Linux 上で稼働している Chrome や、Windows 上で稼働している Edge など、複数の環境で実行することが可能です。もし複数の環境にてテストシナリオを実行することが必要な場合は、「テストシナリオ x 実行環境ごとに異なるログインユーザを使用する」という方法となります。

ModeratorにおけるAutify向けの認証基盤

Moderator ではイベント開発者向けのユーザ認証として Google アカウントを利用しています。ただし、テストシナリオごとに Google アカウントを発行することは現実的ではありません。このような Google アカウント発行が規約違反になるリスクがあります。また、Autify からのアクセスのみ認証を成功とすべきです。

そこで、Autify のテストシナリオで使われるユーザアカウントは、Google アカウントを使わずに、Firebase Authentication のメールアドレス/パスワード方式を使って、ユーザアカウントを作成することにしました。そして、Autify のテストシナリオからのみ利用可能なログイン画面を作りました。Autify 以外からのアクセスに対する保護には、IP アドレスを使ったチェック処理を入れてあります。

テストシナリオを追加する際には、まずスクリプトを使って、Autify 向けのユーザアカウントを作成します。例えば、10 個目のテストシナリオで Linux 上の Chrome 向けのユーザアカウントの場合は、 scenario-10-chrome-linux@tably.rocks を作成します。

各テストシナリオでは、最初に Autify 向けのログイン画面に遷移して、Autify 向けに作成したユーザアカウントの ID とパスワードを入力するようにしています。

画像8

その際に、User-agent によって環境を判断し、ユーザアカウントを切り替えるようにしています。具体的には、以下のような JavaScript を仕掛けてあります。

var userAgent = window.navigator.userAgent.toLowerCase();
if (userAgent.indexOf('x11; linux x86_64') !== -1) {
 return 'scenario-10-chrome-linux@tably.rocks';
} else if (userAgent.indexOf('windows nt 10.0; win64; x64') !== -1) {
 return 'scenario-10-edge-windows@tably.rocks';
} else {
 throw new Error('Unknown user agent: ' + userAgent);
}

あとは、そのテストシナリオは「隔離」された世界ですので、Race condition など気にせずにテストシナリオを作っていくことができます。

テストシナリオごとにユーザアカウントを作成して利用することのメリットとして、「安全にテストデータを初期化することができる」ということもあげられます。テストシナリオによっては、実行の途中で失敗したときに、テストデータを初期状態に戻さなければなりません。Autify の Webhook により全てのテストシナリオの実行が終わったときに、テストデータの初期化処理を呼び出すように設定してあります。対象となるユーザアカウントに関連した情報を初期化対象にすれば良いので、初期化処理を単純にすることが可能です。

Moderator では、ユーザアカウントとテストシナリオをうまく関連付けることで、「メンテナンス性良く」「安全で」「低コストで」を実現した環境を作ることができています。

まとめ

このエントリでは、Autify をより活用するために、テストシナリオを「メンテナンス性良く」「安全で」「低コストで」作成していくための工夫として、ユーザアカウントをうまく使った方法を紹介させていただきました。

Moderator が提供している機能の特性が、ユーザアカウントの分離による工夫にマッチしていたということが幸運だったかもしれません。しかし、おそらくほとんどのウェブサービスではユーザ認証が行われていると思いますので、上記のストーリーは皆さんのシステムにも同じアプローチを適用できるのではないか、と想像しています。

「メンテナンス性良く」「安全で」「低コストで」これらがキーワードかと思います。ぜひ Autify をより活用していくために、このキーワードを参考に環境改善を行ってみてはいかがでしょうか?