eyecatch
Wed, Jul 12, 2017

2017年夏、Selenium、ヘッドレスブラウザ

現在仕事でServiceNow上で動くアプリケーションを開発していて、それのブラウザテストをどうやろうかというのを少し考えたので、書き残しておく。 (adsbygoogle = window.adsbygoogle || []).push({}); ServiceNowとは 本題とほとんど関係ないけど、一応ServiceNowに簡単に触れる。 ServiceNowはITサービス管理のSaaS。 世界的にはITサービス管理のデファクトスタンダードとなっているが、日本ではこれから盛り上がりそうといった感じ。 アプリケーションを開発するプラットフォームとしての側面もあり、JavaScript(ブラウザ側とサーバ側両方)でServiceNowの機能を拡張し、他システムと連携させたり処理を自動化したりできる。 アプリケーションがServiceNowプラットフォームで動くので、テスト方法が悩ましい。 Automated Test Frameworkというテストフレームワークが提供されてはいるが、2017年1月にリリースされたばかりということもあるのか、機能がしょぼく、大したことはできない。 これが自前でブラウザテスト環境を作ろうと思った理由。 アプリケーションがJavaScriptなので、テストもJavaScriptで書きたい。 ブラウザテストとは ここでブラウザテストとは、稼働しているWebアプリケーションに、HTTPクライアントで接続して、レンダリングされたWebページを操作して実行する自動E2Eテストのこととする。 HTTPでWebコンテンツを取得して、HTML・CSSをパースしてレンダリングして、JavaScriptを実行するツール、つまりWebブラウザを何にするかというのと、それを自動で操作するのをどうするかというのと、テストどう書くのかということと、書いたテストをどう実行するかということと、テスト結果をどう集計してレポートするかといった辺りを考える必要がある。 Qiitaの記事「ブラウザテストツール総まとめ・2016年夏版」にブラウザテストのためのツールが色々載っている。 レイヤや目的が異なるツールがちょっとごっちゃになってる気がするけど。 SeleniumとかWebDriverとか ブラウザテストはWebDriver抜きでは語れないので、とりあえずそれについて書く。 それにはまずSeleniumについて語らなければなるまい。 ブラウザテスト創世記にはこうある。 神は「光あれ」と言われた。 するとSeleniumがあった。 神はその光を見て、良しとされた。 神はその光と闇とを分けられた。 神は光をSelenium RC (aka Selenium 1)と名づけ、 闇 をSelenium WebDriver (aka Selenium 2)と名づけられた。 (Seleniumの歴史をもっとちゃんと知りたければこの記事を読むべし。) 要は、今ブラウザテストと言ったらSelenium、Seleniumと言ったらSelenium WebDriverというわけだ。 Selenium WebDriverは、WebDriver APIでブラウザやDOMエレメントを操作するツール。 このAPIを実装したクライアントライブラリが各言語(Java、Ruby、Python、JavaScriptなど)で提供されていて、テストコードから利用できる。 APIの裏ではドライバなるものが暗躍していて、OSやブラウザのネイティブAPIを使ってブラウザを操作している。 このドライバはブラウザごと(Chrome、Firefox、IEなど)に用意されていて、その実装形式がドライバ毎に割と違っている。 例えばFirefox用のやつ(Firefox Driver)はFirefox のアドオンを使うし、Chrome用のやつ(ChromeDriver)は独立したネイティブアプリを介してブラウザを操作する。 ドライバは(基本的に)ブラウザと同じマシンにある必要があり、実行するテストコードとも(基本的に)同居している必要がある。 テストを実行するマシンとは別のマシンのブラウザでテストしたければSelenium Server (aka Selenium Standalone Server)を使う。 Selenium Serverはブラウザとドライバと同じマシンで動き、テストコードから送信されたブラウザ操作コマンドを受信してドライバに伝える、プロキシ的な働きをしてくれる。 Selenium Serverを使えば、クライアントライブラリが対応していないドライバでも利用できるというメリットもある。 Selenium Serverを使うと、オーバーヘッドはあるけどメリットが多いので、とりあえず使うようにしておけば間違いなさそう。 Selenium Serverが受け取るブラウザ操作コマンドは、HTTPでJSONデータとして送信される。 この辺りの通信は、もともとJsonWireProtocol (aka