Jobeetをやってみる 8日目
テスト用メソッド
値比較用
メソッド名 | 説明 | |
---|---|---|
ok($test) | $test == true | |
is($value1, $value2) | $value1 == $value2 | |
isnt($value1, $value2) | $value1 != $value2 | |
like($string, $regexp) | preg_match($regexp, $string) != 0 | |
unlike($string, $regexp) | preg_match($regexp, $string) == 0 | |
is_deeply($array1, $array2) | $array1 == $array2 |
その他の便利なメソッド
メソッド名 | 説明 |
---|---|
fail($msg) | 常にfailになる(Exceptionのテストに便利) |
pass($msg) | 常にpassになる(Exceptionのテストに便利) |
skip($msg, $nb_tests) | $nb_tests数分スキップする(条件付きテストに便利) |
todo($msg) | テストがまだ未実装の場合用 |
comment($msg) | テストを実行した場合のコメント |
テストしてみる
<?php // test/unit/JobeetTest.php require_once dirname(__FILE__).'/../bootstrap/unit.php'; $t = new lime_test(1, new lime_output_color()); $t->pass('This test always passes.');
$ ./symfony test:unit Jobeet
slugifyのテスト
以下のようなテスト
入力値 | 期待する出力 |
---|---|
Sensio Labs | sensio-labs |
Paris, France | paris-france |
<?php // test/unit/JobeetTest.php require_once dirname(__FILE__).'/../bootstrap/unit.php'; $t = new lime_test(6, new lime_output_color()); $t->is(Jobeet::slugify('Sensio'), 'sensio'); $t->is(Jobeet::slugify('sensio labs'), 'sensio-labs'); $t->is(Jobeet::slugify('sensio labs'), 'sensio-labs'); $t->is(Jobeet::slugify('paris,france'), 'paris-france'); $t->is(Jobeet::slugify(' sensio'), 'sensio'); $t->is(Jobeet::slugify('sensio '), 'sensio');
$ ./symfony test:unit Jobeet
エラーが起こったときはどうなるかというと、最後の文がFailed testとなり、エラーに関する情報を出力してくれる。
みたい場合はどれか$t->fail()を追加してみる
テストに何をしたのかさっぱりなので、テストの説明を出力してみる
<?php // test/unit/JobeetTest.php require_once dirname(__FILE__).'/../bootstrap/unit.php'; $t = new lime_test(6, new lime_output_color()); $t->comment('::slugify()'); $t->is(Jobeet::slugify('Sensio'), 'sensio', '::slugify() converts all characters to lower case'); $t->is(Jobeet::slugify('sensio labs'), 'sensio-labs', '::slugify() replaces a white space by a -'); $t->is(Jobeet::slugify('sensio labs'), 'sensio-labs', '::slugify() replaces several white spaces by a single -'); $t->is(Jobeet::slugify(' sensio'), 'sensio', '::slugify() removes - at the beginning of a string'); $t->is(Jobeet::slugify('sensio '), 'sensio', '::slugify() removes - at the end of a string'); $t->is(Jobeet::slugify('paris,france'), 'paris-france', '::slugify() replaces non-ASCII characters by a -');
コードカバレッジ
テストされていない行を検出するための機能
$ ./symfony test:coverage test/unit/JobeetTest.php lib/Jobeet.class.php実行されていない行数を知りたい場合は
$ ./symfony test:coverage --detailed test/unit/JobeetTest.php lib/Jobeet.class.php
Jobeetクラスはslugify()しか持っていないので、適当にfoo()メソッドでも追加してから実行すると分かりやすい
新しい要素のためのテストの追加
先にテストを追加することで、これから実装するコードが既に実装されているかどうか判別できると共に、実装後に期待通りの結果になっていることに自信をもてる
以下のテスト項目を追加
<?php // test/unit/JobeetTest.php $t = new lime_test(7, new lime_output_color()); // ... $t->is(Jobeet::slugify(''), 'n-a', '::slugify() converts the empty string to n-a');
Jobeet::slugify()の始めに以下のコードを追加
<?php // lib/Jobeet.class.php public static function slugify($text) { if (empty($text)) { return 'n-a'; } // ... }
実行してもテストには成功する
$ ./symfony test:coverage --detailed test/unit/JobeetTest.php lib/Jobeet.class.php
バグのためのテスト
先程追加した処理では完全に空文字を防ぐことができていないことが、以下のテストで判明する
<?php // test/unit/JobeetTest.php $t = new lime_test(8, new lime_output_color()); // ... $t->is(Jobeet::slugify(' - '), 'n-a', '::slugify() converts a string that only contains non-ASCII characters to n-a');
このテストを実行するとFailedになる。
原因は先に空文字チェックを行い、その後で非アスキー文字の除去を行っているから。
解決するには、空文字チェックを非アスキー文字の除去後に行えばよい。
<?php // lib/Jobeet.class.php public static function slugify($text) { // ... if (empty($text)) { return 'n-a'; } }
実際にslugify()をより良くするためにはどうすればいいかが記述されているが、日本語を扱うのがほとんどなので、ちょっとした参考程度でいいかなと。
Doctrineを使った単体テスト
DBの設定
# config/databases.yml dev: doctrine: class: sfDoctrineDatabase test: doctrine: class: sfDoctrineDatabase param: dsn: 'mysql:host=localhost;dbname=jobeet_test' all: doctrine: class: sfDoctrineDatabase param: dsn: 'mysql:host=localhost;dbname=jobeet' username: root password: null
devは作成されないが、コマンドでやると以下の手順
$ ./symfony configure:database --name=doctrine --class=sfDoctrineDatabase --env=test "mysql:host=localhost;dbname=jobeet_test" root root $ mysqladmin -uroot -p create jobeet_test $ ./symfony doctrine:insert-sql --env=test
テストデータの作成
今回は本番用のデータを利用するので、data/fixtures からコピーする
$ cp -ap data/fixtures test/
そして、Doctrineの単体テスト用のファイルを作成する
<?php // test/bootstrap/Doctrine.php include(dirname(__FILE__).'/unit.php'); // frontendアプリケーションのtest用の設定を取得 $configuration = ProjectConfiguration::getApplicationConfiguration( 'frontend', 'test', true); // DatabaseManagerの作成により、databases.ymlを読み込む new sfDatabaseManager($configuration); // テスト用のデータを読み込むために、doctrine:data-loadタスク // でも利用されている、Doctrine::loadData()を利用する Doctrine::loadData(sfConfig::get('sf_test_dir').'/fixtures');
JobeetJobクラスのテスト
<?php // test/unit/model/JobeetJobTest.php require dirname(__FILE__).'/../bootstrap/Doctrine.php'; $t = new lime_test(3, new lime_output_color()); $t->comment('->getCompanySlug()'); $job = Doctrine::getTable('JobeetJob')->createQuery()->fetchOne(); $t->is($job->getCompanySlug(), Jobeet::slugify($job->getCompany()), '->getCompanySlug() return the slug for the company'); $t->comment('->save()'); $job = create_job(); $job->save(); $expiresAt = date('Y-m-d', time() + 86400 * sfConfig::get('app_active_days')); $t->is(date('Y-m-d', strtotime($job->getExpiresAt())), $expiresAt, '->save() updates expires_at if not set'); $job = create_job(array('expires_at' => '2008-08-08')); $job->save(); $t->is(date('Y-m-d', strtotime($job->getExpiresAt())), '2008-08-08', '->save() does not update expires_at if set'); function create_job($defaults = array()) { static $category = null; if (is_null($category)) { $category = Doctrine::getTable('JobeetCategory') ->createQuery() ->limit(1) ->fetchOne(); } $job = new JobeetJob(); $job->fromArray(array_merge(array( 'category_id' => $category->getId(), 'company' => 'Sensio Labs', 'position' => 'Senior Tester', 'location' => 'Paris, France', 'description' => 'Testing is fun', 'how_to_apply' => 'Send e-Mail', 'email' => 'job@example.com', 'token' => rand(1111, 9999), 'is_activated' => true, ), $defaults)); return $job; }
もし ok ではなく dubious が出たら、全てのテストが実行される前にスクリプトが終了している可能性があるので、チェックすること