Symfony 1.4で実装したAPIのFunctionalテストをする際に、ファイルをPOSTする方法に迷ったので調べました。
ファイルのアップロードテストは、通常のWebサイトであれば、
$browser->
get('/upload')->
click('Upload', array('form' => array(
'file1' => sfConfig::get('sf_test_dir').'/datas/test01.jpg',
)))
;
みたいに書くのですが、テストしたいアプリケーションはAPIなので、GETするページはありません。
sfBrowserBase::clickを参考にして、こんな感じで実装しました。
まずはテスト本体。test/functional/api/hogeActionsTest.php
<?php
include(dirname(__FILE__).'/../../bootstrap/functional.php');
$browser = new MyTestFunctional(new myBrowser());
$browser->loadData();
$browser->
info('JPEGファイルをアップロードできる')->
setUploadFile('file1', sfConfig::get('sf_test_dir').'/datas/test01.jpg')->
post('/upload', array('title' => 'hoge'))->
with('response')->begin()->
isStatusCode(200)->
end()->
;
次にmyBrowserを定義します。lib/test/myBrowser.class.php
<?php
class myBrowser extends sfBrowser
{
public function setUploadFile($key, $filename)
{
if (is_readable($filename))
{
$fileError = UPLOAD_ERR_OK;
$fileSize = filesize($filename);
}
else
{
$fileError = UPLOAD_ERR_NO_FILE;
$fileSize = 0;
}
$this->parseArgumentAsArray($key, array(
'name' => basename($filename),
'type' => '',
'tmp_name' => $filename,
'error' => $fileError,
'size' => $fileSize,
),
$this->files);
}
}
sfBrowserBaseクラスのfilesに対して配列でファイルの情報を書き込むと、POST直前に$_FILESに書きこんでくれます。
で、あとはMyでmyBrowser::setUploadFileを呼び出すだけです。lib/test/MyTestFunctional.class.php
<?php
class MyTestFunctional extends sfTestFunctional
{
public function loadData()
{
$doctrine = Doctrine_Manager::getInstance()->getCurrentConnection()->getDbh();
$doctrine->query('SET FOREIGN_KEY_CHECKS = 0');
$doctrine->query('TRUNCATE TABLE uploads');
$doctrine->query('SET FOREIGN_KEY_CHECKS = 1');
unset($doctrine);
Doctrine::loadData(sfConfig::get('sf_test_dir').'/fixtures/');
return $this;
}
public function setUploadFile($key, $filename)
{
$this->browser->setUploadFile($key, $filename);
return $this;
}
}
こうやってsetUploadFile(…)->post(…)と呼び出せばOKです。
sfBrowserBase::callされるたびにfilesの中身はクリアされます。