WebKit について (テスト)

テストについて。テストは、 Layout tests と呼ばれるもので行なわれています。 LayoutTests というディレクトリに入っています。これはテストの html を用意しておいて、それに対してどういうふうに rendering する予定であるかをあらわす render tree というものをテキストとして出力させて、それに対してテストを増やす時に置いておいた expectation との diff を取って diff が無ければテスト成功という感じで行なうテストです。

テストは、緑背景に PASS と書いてあるなど、見た目で成功しているか失敗しているかがぱっとわかるテストが好まれるようです。例えばこんな感じ: http://lt.shinh.org/t.html#t=css2.1/t0801-c412-hz-box-00-b-a

元々はその render tree の比較しかなかったのですが、その後だんだんと進化していったようです。主に以下の3点でしょうか。

  • 文字に影をつけるなどの絵で評価しないとイマイチ意味の無いテストもあるので expectation を画像として残すこともできるようになった。
  • render tree や画像の比較は環境によって結果が変わる上に何をテストしているのかが不明確な場合があるので、 layoutTestController.dumpAsText() という関数を呼ぶと document.body.innerText をダンプするモードになって、 portable なテストになる。 JavaScript のテストなんかはこのモードで十分。
  • 指定した user script を追加するとか、リソースの読み込み状況をダンプするとか、そういう普通のブラウザ上の JavaScript だけでは実現できないような機能を layoutTestController のメソッドとして追加。

基本的にはよくできたシステムではあるのですが、いくつか問題点があります。

  • Ruby なんかも同じですが、 unit test ではないのでどうしても複数の挙動を同時にテストしてしまっていることが多い。だから壊れたテストを見ても何が悪いかを即座に断定することがちょっと難しい。
  • バレージもそう高くはない。
  • dumpAsText() を呼んでないテストの expectation は環境依存になるので、それぞれの platform で expectation を生成しないといけない。テストをちょっといじると expectation は生成しなおし。
  • 画像は特に expectation がアテにならない。フォントとか GPU が違うとすぐに一致しなくなるので大変。
  • 正しくない expectation が結構ある。主に画像の update し忘れなど。
  • 環境によって実装されていない layoutTestController のメソッドがある。
  • flaky なものが結構ある。 buildbot はテストを VM の不正確なクロックの上で行なう関係で setTimeout を呼ぶテストがたまに失敗する、とかが典型例。

特に platform ごとに expectation を用意しなければならないのは面倒なので、最近はなるべく dumpAsText() でテストできるようにしているようです。 Firefox は ref test と呼ばれる、二つの html を rendering してみてその結果が一致すれば OK 、とかするテストがあって、こういうシステムを導入したらだいぶ良くなるよねーというのは考えてはいるようです。

テストはブラウザ自体を動かすのではなくて、 DumpRenderTree という WebKit を使って render tree をダンプしたりするアプリケーションによって行なわれています。 DumpRenderTree は WebKit API を使うアプリケーションのサンプルとしてそれなりに参照できたりします。

LayoutTests は1万個以上あるのですが、 DumpRenderTree をそのたびに起動しなおすと遅いので、デフォルトではテスト1000個ごとに DumpRenderTree を起動しなおす感じでテストを走らせています。1000個越えるとメモリリークチェッカがクラッシュするらしいです。アホか。

というわけで複数のテストが同じプロセスで動くので、多少わかりにくいテスト失敗が起きることがあります。典型的なのはデストラクタでクラッシュするバグがある時に、実際にバグを再現しているテストの次のテストの実行中にクラッシュしているように見えることがあるというものです。

記憶にあるもので面白かったものに、 A というテストが DumpRenderTree の最初に実行された場合は DumpRenderTree のバグで JavaScript の状態を残してしまうテストで、 B というテストがその状態が残っていると結果がおかしくなるものがありました。再現条件がレアなため、長い間発見されずにいたのですが、ある時私が全然関係ないテストを一個追加する patch をコミットしようとすると、ちょうど A がその1000個のクラスタの先頭に来て、全然関係ないように見える B がぶっ壊れるためコミットできない、という状態になりました。 A に関しては正常に通ってるように見えるし、 A を一緒にテストしなければ B は正常だし、 A と B を一緒にテストしても A が先頭に来てないと正常に通るし…ということで、 A を特定するのは結構手間でした。

そんなこんなで、まぁ基本的にはよくできているものの、問題は色々あるなーという感じの仕組みです。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h