September 6, 2014

phpunit-seleniumでテスト失敗時にスクリーンショットを撮る。スクリーンショットのファイル名をカスタマイズする。

基本的には https://phpunit.de/manual/4.2/ja/selenium.html の "例 13.3: テストに失敗したときのスクリーンショットの取得" の通りです。

以下の3つのプロパティを適切に設定すれば、テスト失敗時にスクリーンショットが作成されます。
protected $captureScreenshotOnFailure = true;
protected $screenshotPath = '/var/www/localhost/htdocs/screenshots';
protected $screenshotUrl = 'http://localhost/screenshots';
ただし、これだけだとスクリーンショット名が、自動で決まる文字列の羅列になってしまい、どのテストで失敗したのかわかりにくいです。なのでカスタマイズしてみます。

スクリーンショット名は https://github.com/giorgiosironi/phpunit-selenium/blob/master/PHPUnit/Extensions/SeleniumTestCase.php の takeScreenshot() で決まるようです。スクリーンショットディレクトリを返すメソッド "$this->getScreenshotPath()" が呼ばれていて、このメソッドはたぶんここでしか使われていないので、オーバーライドしてみました。

まとめると、以下のようになります。$screenshotPath は、とりあえず "__DIR__" にしています。$screenshotUrlは、とりあえずドキュメントの通りです。(これどんな意味があるのだろうか。)
protected $captureScreenshotOnFailure = true;
protected $screenshotPath = __DIR__;
protected $screenshotUrl = 'http://localhost/screenshots';

/**
 * {@inheritdoc}
 */
protected function getScreenshotPath()
{
    $className = end(explode('\\', get_class()));
    $methodName = \PHPUnit_Framework_Testcase::getName(false);

    return parent::getScreenshotPath().sprintf('%s_%s_', $className, $methodName);
}
テストを失敗させて "{クラス名}_{メソッド名}_{文字列の羅列}.png"が作成されればOKです。

takeScreenshot()のオーバーライドだと丸ごと書かないといけないので、この方法を選びました。getScreenshotPath()というメソッド名の意味合いは変わってしまいますが、まあ、テストケースなので良いかなと。

Macでphpunit-seleniumを動かすメモ

Mac OS X Mavericksで確認しています。

この記事の手順では brew, composer, phpunit 等が予め必要です。

Selenium Serverをインストールします。
$ brew install selenium-server-standalone
Selenium Serverを起動します。
$ selenium-server
適当な場所にディレクトリを作って https://github.com/giorgiosironi/phpunit-selenium をインストールします。
$ composer require phpunit/phpunit-selenium:1.*
適当なテストケースを書きます。
$ more ExampleTest.php
<?php
require_once 'vendor/autoload.php';
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class ExampleTest extends PHPUnit_Extensions_SeleniumTestCase
{
    public static $browsers = [
        ['name' => 'Firefox', 'browser' => '*firefox'],
        ['name' => 'Chrome',  'browser' => '*googlechrome'],
    ];

    protected function setUp() {
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle() {
        $this->open('http://www.example.com/');
        $this->assertTitle('Example Domain');
    }
}
ブラウザ名の先頭につけるAsteriskについて http://stackoverflow.com/questions/7405498/in-selenium-1-why-are-all-the-browser-commands-prefixed-with-an-asterix に記載がありました。まだよく理解していませんが。。。

実行してみます。
$ phpunit ExampleTest.php
PHPUnit 4.2.4 by Sebastian Bergmann.

..

Time: 7.01 seconds, Memory: 5.25Mb

OK (2 tests, 2 assertions)
FirefoxとChromeが起動してテストが実行されました。

テストの書き方はPHPUnitのマニュアル https://phpunit.de/manual/4.2/ja/selenium.html に記載されています。

思っていたより簡単で良かった。

August 16, 2014

Knockout.jsのforeachで少しハマったのでメモ

最近、ぶっつけ本番でKnockout.jsを使っていて、foreachの動きで少しハマったのでメモ。(慣れている人にとっては大したこと無い内容なんだろうけど。。。)

サンプルソースは以下です。
<html>
<head>
    <script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>
</head>
<body>
<!-- foreach をネストする際、内側の foreach で使用する配列に "$root" をつけないとエラーになる  -->
<div data-bind="foreach: {data: array1, as: '$value1' }">
    <p data-bind="text: $value1"></p>
    <div data-bind="foreach: {data: $root.array2, as: '$value2' }">
        <p data-bind="text: $value2"></p>
    </div>
</div>

<!-- "$index" は単独だと出力できるが、文字列連結時等は "$index()" としないとエラーになる  -->
<!-- "$parentContext.$index" も同様  -->
<div data-bind="foreach: {data: array1, as: '$value1' }">
    <p data-bind="text: $index"></p>
    <p data-bind="text: $index() + ':' + $value1"></p>
    <div data-bind="foreach: {data: $root.array2, as: '$value2' }">
        <p data-bind="text: $parentContext.$index"></p>
        <p data-bind="text: $parentContext.$index() + ':' + $value2"></p>
    </div>
</div>

<script>
    function ViewModel() {
        var self = this;
        
        self.array1 = ko.observableArray(['foo', 'bar', 'baz']);
        self.array2 = ko.observableArray(['FOO', 'BAR', 'BAZ']);
    };

    ko.applyBindings(new ViewModel());
</script>
</body>
</html>

コメントに書いてある通りですが

1.
foreach をネストする際、内側の foreach で使用する配列に "$root" をつけないとエラーになる

2.
"$index" は単独だと出力できるが、文字列連結時等は "$index()" としないとエラーになる("$parentContext.$index" も同様)

で、ハマった。。。


P.S.
まだほんの少し使った程度ですが、JSはjQueryがメイン。という開発の中に、双方向バインディングだけ付け足したい時とかは便利かなと思いました。jQueryの処理も好きに書いて良い(という思想な)はずなので、例えばチームのメンバ的に、AngularJSだと(主にディレクティブ周りで)敷居が高くなってしまい導入に躊躇するような状況でも、Knockout.jsなら比較的楽に導入出来る気がします。(制約が緩いほど秩序は保ちにくくなってしまうはずですが。)



August 6, 2014

Chromeのオートコンプリートを個別に削除するメモ

メモ。

オートコンプリートリストの該当選択肢にカーソルを併せて
Windowsの場合は shift + delete
Macの場合は fn + shift + delete
で出来ました。

August 2, 2014

Macでidn_to_ascii()とidn_to_utf8()を使えるようにする

メモです。

icu4cとintlパッケージをインストールします。
brew install icu4c
sudo pecl install intl # ライブラリのパスは /usr/local/Cellar/icu4c/{VERSION} でした
php.iniに以下を記述します。(バージョン周りは適宜置換)
extension=/usr/local/Cellar/php54/5.4.25/lib/php/extensions/no-debug-non-zts-20100525/intl.so