September 6, 2014

Laravel4.3(5.0?)のディレクトリ構成の変更メモ

4.3でなく5.0にする案も出ているみたいですが、どうなるかよくわからないので、とりあえず4.3と呼びます。

近々、4.3を使う気がするので、ディレクトリ構成の変更について調べてみました。時期的に、4.3正式リリースの少し前になると思うんですが、4.2からのアップグレードは面倒そうなので、4.3でスタートした方が良いかなぁ。と。

https://laracasts.com/series/whats-new-in-laravel-4-3 の動画が大変参考になりました。

尚、4.3はまだ開発段階なので、多少は変わる結構変わる可能性もあると思います。

まず、appディレクトリ。
app
├── Console ... app/commands に相応
├── Http
│   ├── Controllers ... app/controllers に相応
│   ├── Filters ... app/filters.php で指定していたフィルタ処理のクラス群
│   ├── Requests ... 新機能。1リクエストに対するバリデーションルールや認証ロジック等を持つクラスを実装する
│   └── routes.php ... app/routes.php に相応
├── Providers ... グローバル空間で行われていた色々な処理がプロバイダとしてまとめられた
└── User.php ... app/models/User.php に相応
appディレクトリはcomposer.jsonのPSR-4で指定されています。
"psr-4": {
    "App\\": "app/"
}
名前空間プリフィックスである "App" が嫌な場合は "app:name" で変更できます。
$ php artisan app:name Foo
動画にもあるように app/Http/Requests に実装するクラスは、コントローラメソッドにインジェクションして使うと便利そうです。コントローラメソッドへのインジェクションも、4.3からの新機能です。

次に、その他のディレクトリ。
bootstrap
├── environment.php ... 環境を決める処理がここに切り出された

config ... app/config に相応
├── filesystems.php ... 4.3で新たに組み込まれたファイルシステムに対する設定
├── namespaces.php ... appディレクトリ以下のクラスに対して使用される名前空間の設定

database app/database ... に相応

resources
├── lang app/lang ... に相応
└── views app/views ... に相応

storage app/storage ... に相応

4.2までappディレクトリにあった多くのディレクトリがプロジェクトルートに移動されています。appディレクトリに作成するファイルは、基本的には、アプリケーションを動かすためのクラスのみ。となった感じですかね。

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 に記載されています。

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