Jobeetをやってみる 9日目
機能テストについて学ぶ
テスト用のデータは test/fixtures にあるものを利用するようにするけど、中身は data/fixtures と一緒。
sfBrowserクラスについて
ブラウザの動作をシミュレートするメソッド
メソッド名 | 説明 |
---|---|
get($uri, $parameters, $changeStack) | GETメソッドによるリクエスト |
post($uri, $parameters, $changeStack) | POSTメソッドによるリクエスト |
call($uri, $method, $parameters, $changeStack) | PUTとDELETEメソッドを利用したリクエスト |
back() | 履歴の戻る |
forward() | 履歴の進む |
reload() | 更新 |
click($name, $arguments, $options) | リンクやボタンをクリックした動作 |
select($name) | ラジオボタンやチェックボックスの選択 |
deselect($name) | ラジオボタンやチェックボックスの選択解除 |
restart() | ブラウザの再起動 |
ブラウザの設定に関するメソッド
メソッド名 | 説明 |
---|---|
setHttpHeader($header, $value) | HTTPヘッダの追加 |
setAuth($username, $password) | Basic認証の認証設定 |
setCookie($name, $value, $expire, $path, $domain, $secure, $httpOnly) | Cookieの追加 |
removeCookie($name) | Cookieの削除 |
clearCookies()*1 | 全てのCookieの削除 |
followRedirect() | Locationヘッダによるリダイレクト |
使用例
<?php $browser = new sfBrowser(); $browser-> get('/')-> click('Design')-> get('/category/programming?page=2')-> get('/category/programming', array('page' => 2))-> post('search', array('keywords' => 'php')) ;
sfTestFunctionalクラス
sfBrowserクラスを利用して、実際にテストを行なうクラス。
sfBrowserもそうだけど、sfTestFunctionalも流れるようなインターフェイスで記述できる。
categoryActionsTest.php
既にgenerate:moduleで以下のような機能テスト用ファイルが作られている。
<?php // test/functional/frontend/categoryActionsTest.php include(dirname(__FILE__).'/../../bootstrap/functional.php'); $browser = new sfTestFunctional(new sfBrowser()); $browser-> get('/category/index')-> with('request')->begin()-> isParameter('module', 'category')-> isParameter('action', 'index')-> end()-> with('response')->begin()-> isStatusCode(200)-> checkElement('body', '!/This is a temporary page/')-> end() ;
begin()からend()までが所謂ブロックとなる。
しかしブロックが必須というわけではなく、1つだけの機能をテストするのであれば
<?php $browser-> with('request')->isParameter('module', 'category')-> with('response')->isStatusCode(200)-> ;のように書くこともできる
テストコード
細々してどこで何をやってるかイメージしづらいし、どうせテストはその時に応じて変更されるので一気にやる
本家では loadData() を作成してテスト時にデータをロードするようにしてるけど、2回目以降でエラーになってしまうのでちょっとだけ変更
<?php // test/functional/frontend/jobActionsTest.php include(dirname(__FILE__).'/../../bootstrap/functional.php'); $browser = new JobeetTestFunctional(new sfBrowser()); $browser->info('1 - The homepage')-> get('/')-> with('request')->begin()-> isParameter('module', 'job')-> isParameter('action', 'index')-> end()-> with('response')->begin()-> info(' 1.1 - Expired jobs are not listed')-> checkElement('.jobs td.position:contains("expired")', false)-> end() ; $max = sfConfig::get('app_max_jobs_on_homepage'); $browser->info('1 - The homepage')-> info(sprintf(' 1.2 - Only %s jobs are listed for a category', $max))-> with('response')-> checkElement('.category_programming tr', $max) ; $browser->info('1 - The homepage')-> get('/')-> info(' 1.3 - A category has a link to the category page only if too many jobs')-> with('response')->begin()-> checkElement('.category_design .more_jobs', false)-> checkElement('.category_programming .more_jobs')-> end() ; $browser->info('1 - The homepage')-> info(' 1.4 - Jobs are sorted by date')-> with('response')->begin()-> checkElement(sprintf('.category_programming tr:first a[href*="/%d/"]', $browser->getMostRecentProgrammingJob()->getId()))-> end() ; $browser->info('2 - The job page')-> info(' 2.1 - Each job on the homepage is clickable and give detailed information')-> click('Web Developer', array(), array('position' => 1))-> with('request')->begin()-> isParameter('module', 'job')-> isParameter('action', 'show')-> isParameter('company_slug', 'sensio-labs')-> isParameter('location_slug', 'paris-france')-> isParameter('position_slug', 'web-developer')-> isParameter('id', $browser->getMostRecentProgrammingJob()->getId())-> end()-> info(' 2.2 - A non-existent job forwards the user to a 404')-> get('/job/foo-inc/milano-italy/0/painter')-> with('response')->isStatusCode(404)-> info(' 2.3 - An expired job page forwards the user to a 404')-> get(sprintf('/job/sensio-labs/paris-france/%d/web-developer', $browser->getExpiredJob()->getId()))-> with('response')->isStatusCode(404) ;
<?php // lib/test/JobeetTestFunctional.class.php class JobeetTestFunctional extends sfTestFunctional { public function getMostRecentProgrammingJob() { $q = Doctrine_Query::create() ->select('j.*') ->from('JobeetJob j') ->leftJoin('j.JobeetCategory c') ->where('c.slug = ?', 'programming'); $q = Doctrine::getTable('JobeetJob')->addActiveJobsQuery($q); return $q->fetchOne(); } public function getExpiredJob() { $q = Doctrine_Query::create() ->from('JobeetJob j') ->where('j.expires_at < ?', date('Y-m-d', time())); return $q->fetchOne(); } }
<?php // test/functional/frontend/categoryActionsTest.php include(dirname(__FILE__).'/../../bootstrap/functional.php'); $browser = new JobeetTestFunctional(new sfBrowser()); $browser->info('1 - The category page')-> info(' 1.1 - Categories on homepage are clickable')-> get('/')-> click('Programming')-> with('request')->begin()-> isParameter('module', 'category')-> isParameter('action', 'show')-> isParameter('slug', 'programming')-> end()-> info(sprintf(' 1.2 - Categories with more than %s jobs also have a "more" link', sfConfig::get('app_max_jobs_on_homepage')))-> get('/')-> click('27')-> with('request')->begin()-> isParameter('module', 'category')-> isParameter('action', 'show')-> isParameter('slug', 'programming')-> end()-> info(sprintf(' 1.3 - Only %s jobs are listed', sfConfig::get('app_max_jobs_on_category')))-> with('response')->checkElement('.jobs tr', sfConfig::get('app_max_jobs_on_category'))-> info(' 1.4 - The job listed is paginated')-> with('response')->begin()-> checkElement('.pagination_desc', '/32 jobs/')-> checkElement('.pagination_desc', '#page 1/7#')-> end()-> click('2')-> with('request')->begin()-> isParameter('page', 2)-> end()-> with('response')->checkElement('.pagination_desc', '#page 2/7#') ;
テスト用のデータロード
$ ./symfony doctrine:data-load --dir="test/fixtures" --env="test"
デバッグ
テストに失敗したときに、どんなデータが返ってきているのかとか、現在のHTTPヘッダの状態とかを見るために debug() メソッドが用意されている
<?php $browser->with('response')->debug();