Silex のコードを PHPUnit でテストする


[Symfony勉強会 #10](http://symfony.doorkeeper.jp/events/12539) の Silex ワークショップでテストまでやってみました。

--- 

[Testing - Documentation - Silex - The PHP micro-framework based on Symfony2 Components](http://silex.sensiolabs.org/doc/testing.html) を参考に、Silex の簡単なコードを PHPUnit でテストしてみよう！

今回のコードは https://github.com/hideyuki/silex-proj-symfony-study10 で公開しています。



## ファイル構成

以下のようなファイル構成です。

```
app.php
composer.json
composer.lock
phpunit.xml
tests/
    indexTest.php
vendor/
    So many files...
web/
    index.php
```

## メインコード app.php

[Creating a simple REST application with Silex.](http://sleep-er.co.uk/blog/2013/Creating-a-simple-REST-application-with-Silex/) を参考にアプリ部分のコードを書いてみました。

app.php では `$app->run()` せずに `return $app` するように変更。$app はテストコードで require します。

```app.php
<?php

require_once __DIR__ . '/vendor/autoload.php';

$app = new Silex\Application();

$toys = array(
    '00001'=> array(
        'name' => 'Racing Car',
        'quantity' => '53',
        'description' => '...',
        'image' => 'racing_car.jpg',
    ),  
    '00002' => array(
        'name' => 'Raspberry Pi',
        'quantity' => '13',
        'description' => '...',
        'image' => 'raspberry_pi.jpg',
    ),  
);

$app->get('/', function() use ($toys) {

    return json_encode($toys);
});

$app->get('/{stockcode}', function (Silex\Application $app, $stockcode) use ($toys) {

    if (!isset($toys[$stockcode])) {
        $app->abort(404, "Stockcode {$stockcode} does not exist.");
    }   
    return json_encode($toys[$stockcode]);
});

return $app;
```

## テストコード web/indexTest.php

`createApplication` にて、上記の $app を生成。
そして、`testIndex` にテスト内容を記述していきます。

```tests/indexTest.php
<?php

require_once __DIR__.'/../vendor/autoload.php';

use Silex\WebTestCase;

class IndexTest extends WebTestCase
{
  public function createApplication()
  {
    $app = require __DIR__ . '/../app.php';

    $app['debug'] = true;
    $app['exception_handler']->disable();

    return $app;
  }

  public function testIndex()
  {
    $client = $this->createClient();
    $crawler = $client->request('GET', '/');

    # ok?
    $this->assertTrue($client->getResponse()->isOK());

    # check count
    $response = $client->getResponse();
    $data = json_decode($response->getContent(), true);

    $this->assertEquals(2, count($data));
  }
}
```

PHPUnit の対象は `phpunit.xml` に定義しています。(tests ディレクトリ以下)

```phpunit.xml
<phpunit>
  <testsuites>
    <testsuite name="Silex Test">
      <directory>tests</directory>
    </testsuite>
  </testsuites>
</phpunit>
```

そして テスト実行。PHPUnitはcomposerによってvendorに入っています

```terminal
$ ./vendor/bin/phpunit

PHPUnit 4.1.4 by Sebastian Bergmann.

Configuration read from /Users/hide/github/silex-proj-symfony-study10/phpunit.xml

.

Time: 81 ms, Memory: 5.50Mb

OK (1 test, 2 assertions)
```

これでテストができました！

## APPENDIX: ビルトインサーバで実行

`$app->run()` は　web/index.php に記述。

```web/index.php
<?php

require_once __DIR__ . '/../vendor/autoload.php';

$app = require __DIR__ . '/../app.php';
$app['debug'] = true;
$app->run();
```

実行は以下のコマンド (php5.4でビルトインサーバが使えるようになりったようです)

```terminal
$ php -S localhost:8888 -t web

PHP 5.5.15 Development Server started at Sun Jul 27 07:22:49 2014
Listening on http://localhost:8888
Document root is /Users/hide/github/silex-proj-symfony-study10/web
Press Ctrl-C to quit.
```

試しに localhost:8888 にアクセスしてみる。

```terminal
$ curl -i http://localhost:8888

HTTP/1.1 200 OK
Host: localhost:8888
Connection: close
X-Powered-By: PHP/5.5.15
Cache-Control: no-cache
Date: Sat, 26 Jul 2014 22:23:03 GMT
Content-Type: text/html; charset=UTF-8

{"00001":{"name":"Racing Car","quantity":"53","description":"...","image":"racing_car.jpg"},"00002":{"name":"Raspberry Pi","quantity":"13","description":"...","image":"raspberry_pi.jpg"}}
```

OK！