PHPerのゆるふわSelenium
某所某日
お客様「この画面遷移が〜(延々)」俺「はい…」お客様「あっ、そういえばこの画面でこれ追加」俺「はい…」
…
俺「これ画面遷移マジ複雑だし、仕様変更の量半端ないし、これは後でエンバグするやろ…。自動テストしたい…、でもTwitter連携あるからなー。PHPだし…ちゃんとしたMechanizeみたいなのないし*1…seleniumしかないか…」
やった後のイメージ
・複雑なことしなければ超カンタンじゃねーか!だまされた
・PHPで十分や!!!
手順
・SeleniumServerをいれる
・PHPUnitで動くSeleniumのライブラリ入れる
・Seleniumのテストケースを生成するツールをいれる
・テストケース作る
・手元のMacでうごかす
Seleniumを入れる
http://code.google.com/p/selenium/downloads/list
から、selenium-server-standalone-2.33.0.jarをDLする
特にインストールに伴う細かい作業や起動オプションは必要なく、`java -jar selenium-server-standalone-2.33.0.jar` であっさり起動する。
phpunit+ PHPUnit_Extensions_SeleniumTestCaseを入れる
まあ、いっぱんてきなうぇぶえんじにあなら最近のPHP 5.5が入ってるでしょうから、
curl -s http://getcomposer.org/installer | php
この一行でComposerをいれた上で、
あとはcomposer.jsonを作って
{ "require": { "phpunit/phpunit": "3.7.*", "phpunit/phpunit-selenium": "1.3.*" } }
あとはphp composer.phar install 一発で完了です!簡単ですね!!
(composerは、Perlでいうところのcartonみたいなやつです)
テストケースを作成する
selenium builderでひな形作成
必須ではないんですけど、テストケースを手で書くのは結構だるい感じなので、今回selenium builderを使います、FirefoxのAddonです。
http://sebuilder.github.io/se-builder/
Firefox右下に追加される緑ブロックをクリックするとselenium builderのウインドウが立ち上がります。
ここのSelenium1を選択して*2、レコード開始です。
・画面をクリックしたり、入力したり
・"Record a Verifycation" を押してから、チェックしたい画面要素をクリック
・間違えたらルール消したり
とかやってると、ルールがザクザクとできていきます。
正直立派なUIではないのですけど、まあできていきます。
テストケースを実行する
少し修正
生成されたPHPはひな形なので、保存したphpファイルをひらいて修正します。
今回composerつかったので、最初のローダ行を
require_once "vendor/autoload.php";
などと修正し、
$this->setBrowser('*chrome');
をとりあえず「*firefox」に修正します。
そうすると
<?php require_once __DIR__ . '/../vendor/autoload.php'; class Example extends PHPUnit_Extensions_SeleniumTestCase { protected function setUp() { $this->setBrowserUrl('http://www.google.com'); $this->setBrowser('*firefox'); } public function myTest() { $this->open("/"); $this->waitForPageToLoad("60000"); try { $this->assertTrue($this->isTextPresent("google")); } catch (PHPUnit_Framework_AssertionFailedError $e) { array_push($this->verificationErrors, $e->toString()); } } }
こんな感じになりますかね。
実行してみる
$ vendor/bin/phpunit Example PHPUnit 3.7.22 by Sebastian Bergmann. ... Time: 0 seconds, Memory: 5.50Mb OK (1 tests, 1 assertions) $
やった!うごいた!あとは書き足していきましょう!
うごかなかった人、特にSeleniumが「error: Unexpected Exception: Value does not implement interface Event.」とか言う人もいたと思います、というか、今現在最新版のFirefoxを使っていると、言われると思います…。
落とし穴
まあ、一発でうごいたら本当にラッキーですね、いくつか落とし穴がありました。私がハマった穴を紹介します
落とし穴0:Seleniumさんマジせっかち
リンクやボタンを押してページ遷移をさせて、その次のページに要素があるか評価したい、というよくあるケースをつくるとき に、ページロードを待たないで評価してエラーになる事がよくあります。
いわゆるSelenese*3の clickAndWaitにならないで、Clickの次にassertがはいるようなケースをSelenium Builderは生成しがちなので、ここはだるいけど手で修正しましょう。
落とし穴1:Firefox22(最新版)でうごかない
http://code.google.com/p/selenium/issues/detail?id=5841
どうも、最新版のFirefox22では前述の「error: Unexpected Exception: Value does not implement interface Event.」というエラーが出ます。
まずは過去バージョン配布サイト( https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/ ) Firefox 21をDLして、dmgの中のFirefox.appをFirefox_21.appなどとリネームしてどこかに保存し、
$this->setBrowser('*firefox /path/to/Firefox_21.app/Contents/MacOS/firefox');
とか適当に指定すれば、好きな場所のバイナリのFirefoxを使えます。
多分これはselenium-serverのバグなので、そのうちなおると思いますが、だるいですね。
落とし穴2: セッション全部切れる
Seleniumで起動されるブラウザは「素」のものが起動します。Twitter連携アプリ等のログインがあるものののテストをするときは、普段のブラウザでルールをつくると、ログインのフェーズがスッポ抜けてエラーになることがあります。
全部ログアウトしてからルールを作りましょう。
(このあたり、SeleniumBuilderじゃなくて、SeleniumIDEでやると気づきやすいんですよね…)
落とし穴3: Seleniumbuilderはヘボい
一発で良い感じのテストケースができるのは稀な感じあります。
最終的には、生成されたコードをちまちまと書き直し、再実行、書き直し、再実行、とするしかない。
まあ単純な操作ならいいんですけど、途中にリダイレクトがはいるようなサイトだと割りと失敗したりする。しょーーじきダルいですね。
ちなみに、Selenium IDE( http://docs.seleniumhq.org/projects/ide/ ) はルール作成機能が高機能で、使ってみるとBuilderよりもテストケース作成がさくさくできます。
特にステップ実行や、Assertの即時実行などができるのでなんだかんだこちらのほうが楽…。
しかしながら、SeleniumIDEはSelenium 2(Webdriver)向けにつくられているので、Selenium1(RC)むけのPHPテストケース出力とかできないのですよね、辛い。
ただまあ、SeleniumIDE は Javaのひな形なら 1(RC)等へのエクスポートができるので、
それを手動変換って感じかなと思います…ちょっと複雑なテストだと、遠回りのようで、こっちのほうがはやいかも。
(1(RC)と2(Webdriver)は文法が違うので注意)
(まあ、つかって間もない私の感想ですけど、最終的には全部ルール手でかきそうです…)
selenium_1_(RC)と selenium_2_(Webdriver)の話
今回入れたselenium-serverはSelenium2のものなんですが、バックワードコンパチで1(RC)のAPIをサポートしているそうです。
今回つかったPHPUnit_Extensions_SeleniumTestCaseは、1(RC)のAPIで叩くものです。なので、最新のIDEは1をもうサポートしないので、書き出せない、という感じらしいです。
一応PHPにも PHPUnit_Extensions_Selenium2TestCaseというのがあるのですが、一部機能が実装されていないらしいし、IDEもBuilderも対応していないっぽいので、使う意義が私にはみいだせませんでした…
しかも、PHPUnit_Extensions_Selenium2TestCaseはComposerでパッって一発ではいらないっぽいんですよね…。
まあ、いつか2(Webdriver)にせざるをえないのかもしれませんが、しばらくはSeleniumServerは1も2もサポートするっぽいので、当面1(RC)で書こうと思います…。
まとめ
変な所でひっかからなければ、ローカルマシンでのSeleniumのテストは1時間もかからず書き始められます。
PHPはMechanizeがないとか生きるのが辛めと言われますが、SeleniumさえあればTwitterとやたらと連携するようなサービスでも気軽に自動テストできるっぽいのではかどりますね!!
サァ!みんなPHPを書こう!
おまけとお役立ち情報
chromeでテストしたい
http://code.google.com/p/chromedriver/downloads/list
から chromedriver_mac32_2.1.zip などをDLして、でてきたバイナリコマンドをPathが通ってる所に置けばOKです、簡単ですね。
エッ… Perl…?
まあ、私の知り合い大体Perlの人ですからね、しかたないですね…。
(っていうか、このエントリ自体が昨日やったHachioji.pm #30 Takao.mtのLT資料の再編です)
めんどいのではしょりますけど、selenium builderはPerl対応もしてるらしいっすよ?試してないから、しらないけど。
エッ、コード?
#!/usr/bin/env perl use strict; use warnings; use utf8; use Selenium::Remote::Driver; use Test::More; my $driver = Selenium::Remote::Driver->new( browser_name => 'firefox', ); { $driver->get('http://www.google.com'); my $title = $driver->get_title; cmp_ok($title, 'eq', 'Google', 'Test: $title eq "Google"'); } $driver->quit;
$ perl ./test.pl ok 1 - Test: $title eq "Google" # Tests were run but no plan was declared and done_testing() was not seen.
ハイハイ!Perlでもちゃんとうごきますよ!しかもまじ手軽だし、Selenium 2にも対応してるっぽいよ!!!
なんか色々できるしMechanizeのかわりにもつかえそうだね!よかったね!ああよかったね!
PHP仲間を募集しています
是非Hachioji.pmにあそびにきてください、主催だけPHPerで泣きそうです。
http://hachiojipm.org/