Wed, Jul 12, 2017

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

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

現在仕事でServiceNow上で動くアプリケーションを開発していて、それのブラウザテストをどうやろうかというのを少し考えたので、書き残しておく。

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 WebDriver Wire Protocol)で規定されていた。 JsonWireProtocolをW3Cが国際標準規格化したのがWebDriverというプロトコル。 このWebDriverプロトコルは、ユーザエージェントとDOMエレメントをリモートコントロールするためのインターフェースを定めている。 現在、JsonWireProtocolは廃止扱いで、Selenium WebDriverはWebDriverプロトコルを実装している。

この辺り、この記事が図解してて分かりやすい。

ChromeDriverはWebDriverプロトコルを実装してるので、Selenium Server無しでもリモート実行できるけど、それでもやはりSelenium Serverを介したほうが、ドライバを簡単に切り替えられそうでよさそう。

Selenium ServerとかChromeDriverのようにWebDriverプロトコルのサーバ機能を実装したものはRemoteWebDriverServerと呼ばれることもある。 それにアクセスするクライアントはRemoteWebDriverとかRemoteWebDriverクライアントとか呼ばれる。


ということで、色々ややこしい(公式も自分でややこしいと言ってる)が、結局WebDriverは何かと言えば、普通は上記ドライバそのものを指す。 ので、以下においても、WebDriverと書いたらそれを指すこととする。

ヘッドレス

もう一つブラウザテストの文脈で重要なのが、ヘッドレスという概念なので、ここでちょっと触れる。

ヘッドレスとは、ソフトウェアがGUIなしで動く性質とか機能のこと。

ブラウザテストは、テスト実行時にブラウザを起動するわけだが、ブラウザってのは普通GUIが付いていて、Windowsだったらログインしてないと動かせないし、LinuxだったらXの起動も必要だ。 これだと、テストを定期的に自動実行したり、CIしたりするのが難しい。 また、GUIは動作が遅く、テストに時間がかかる。

ヘッドレスブラウザ

こうした問題を解決するため、ヘッドレスブラウザというものが開発された。 ヘッドレスブラウザには以下のようなものがある。

  • PhantomJS

    多分一番有名なヘッドレスブラウザ。 JavaScriptとC++などで書かれていて、JavaScriptから操作できる。 2011年にリリースされ、まだ開発が続いている。 レンダリングエンジンはWebKitで、JavaScriptエンジンはWebKitに組み込みのJavaScriptCoreで、 Windows、OS X、Linuxなどで動く。 WebDriver有り。(Ghost Driver)

  • HtmlUnit

    Chrome、Firefox、IEをシミュレートできるJava製のツールで、 JavaのAPIで操作できる。 2002年にリリースされ、まだ開発が続いている。 レンダリングエンジンは(多分)自前で、JavaScriptエンジンはRhino。 WebDriver有り。(HtmlUnitDriver)

  • Splash

    Python製。2013年に開発がスタートし、現在も鋭意開発中。 LinuxとOS Xをサポートしてて、Windowsでは(多分)動かない。 HTTP APIにJSONをPOSTして操作するもので、Luaのクライアントライブラリが提供されている。 レンダリングエンジンはWebKitで、JavaScriptエンジンはWebKitに組み込みのJavaScriptCore。 WebDriverなさげ。

  • TrifleJS

    JavaScriptとC#(.NET 4.0)で書かれていて、Windowsでしか動かない。 レンダリングエンジンはTridentで、IEをエミュレートする。 JavaScriptエンジンはV8。PhantomJSと同じAPIを実装していて、JavaScriptから操作できる。 2013年に開発がスタートし、ベータ版のまま開発中断してしまった模様。 WebDriverは、ロードマップにはあるけどまだ実装されてない。


あと、似たようなものにSlimerJSElectronjsdomがある。

SlimerJSは、GeckoとSpiderMonkeyの上に開発された、スクリプトから操作できるテスト用途向けブラウザだけど、ヘッドレスではない。

ElectronはJavaScriptでデスクトップアプリケーションを開発するためのフレームワーク。 Chromiumというブラウザを積んでいて、それをElectron APIでプログラマティックに操作できるらしく、ブラウザテストにも使われる。 (Seleniumでも操作できる。) けどこれもヘッドレスではない。

jsdomはDOMツリーとそれに対する操作をエミュレートするツールで、そもそもブラウザではないはずなんだけど、HTTPでWebコンテンツダウンロードして解析もできるし、すごくヘッドレスブラウザっぽい。 けどちゃんとブラウザしてるかが怪しく、UIテストには使われてもブラウザテストにはあまり使われないっぽい。


ヘッドレスブラウザにも色々あるが結局、テスト用に作られたブラウザであって、実際に多くのエンドユーザに使われて揉まれているGUI有りブラウザに比べて、品質が悪かったり動きが違ったりする(らしい)。 JavaScriptのバージョンのキャッチアップが遅かったりも。

Xvfb

ヘッドレスブラウザの問題は、実際のブラウザではないということに尽きる。 実際のブラウザをヘッドレスで使えたら万事が上手くいくわけだが、実はこれがLinuxでなら出来る。 Xvfbというツールを使って。 (XvfbはあまりメンテされてなくてXdummyが代わりに最近熱いみたいだけど。)

Xvfbはフレームバッファをエミュレートし、ディスプレイが無い環境でも動くヘッドレスXサーバ。 これを使うと、GUIのある普通のブラウザでもヘッドレス環境で動かせる。

Xvfbについてはこの記事が分かりやすい。

Chrome 59

Xvfbを使えば大分幸せになりそうだが、ブラウザ以外のツールを起動しなければいけなかったり、Windowsで使えなかったり、まだちょっと不満が残る。

そんななか、2017年6月、Chrome 59がリリースされ、ヘッドレスモードを搭載した。 Windowsは現時点で未対応だけど、すぐに対応されるはずだ。 ほかの実ブラウザもこの流れに乗ってヘッドレスモードを実装したら、最高に幸せな世界になるではないか。

Chromeのヘッドレスモード搭載を受け、PhantomJSは開発停止した。 もうヘッドレスブラウザはその役目を終えつつあるということなのだろう。

Chrome 59のヘッドレスモードの使い方はこの記事が分かりやすい。



以上のような感じのことが調べて分かって、SeleniumとChromeのヘッドレスモードを使いたいと思ったところで、 続きはまた別の記事