概要
CakePHP にはアップロードファイル用の validator が用意されていて便利。
ただテストをするときにちょっとめんどくさい点が2つある。
1つ目はファイルをアップロードするリクエストを作ること。
リクエストするデータとは別に $_FILES にも情報を突っ込んでおかないと、Controller で \Cake\Http\ServerRequest::getUploadedFile あたりを呼び出した時に値が取れなくなる。
もう1つは is_uploaded_file を stub にする必要があること。
uploadedFile の Validation はアップロードファイル判定に is_uploaded_file を使っており、テスト時にこの判定をくぐり抜けるのが難しい。
uploadedFile の Validation
Controller 内で↓のように書ける。便利。
$validator = new Validator(); $validator->uploadedFile( 'my_file', ['types' => ['text/plain']], 'ファイル形式が正しくありません' ); $errors = $validator->errors($this->request->getData());
オプションは mime type 以外にも、サイズ判定などがある。
テストで uploadedFile のリクエストを作る
uploadedFile を Controller のテスト (IntegrationTestTrait) で使う場合、 \Psr\Http\Message\UploadedFileInterface の実装インスタンスを生成してリクエストに乗せる。
\Zend\Diactoros\UploadedFile を使えばいいと思う。
このとき、リクエストデータとは別に $_FILES にもセットしておく必要がある。
直接代入してもいいのだが、 \Cake\TestSuite\IntegrationTestTrait::configRequest に files いうキーで渡してあげると、結果的に同じことができるようだ。
$testFile = TESTS . 'Fixture' . DS . 'files' . DS . 'my_file.txt';
$uploadedFile = new UploadedFile(
$testFile,
10,
UPLOAD_ERR_OK,
'my_file.txt',
'application/octet-stream'
);
// 別途設定する
$this->configRequest(
[
'files' => [
'my_file'=> [
'error' => $uploadedFile->getError(),
'name' => $uploadedFile->getClientFilename(),
'size' => $uploadedFile->getSize(),
'tmp_name' => $testFile,
'type' => $uploadedFile->getClientMediaType(),
]
]
]
);
// リクエスト
$this->post("your/api/", ['my_file' => $uploadedFile]);
ちなみにファイルの中身の確認は ext/finfo で 'tmp_name' に対して行われる。
実ファイルに対してチェックが行われるので、配置しておく必要がある。
is_uploaded_file を stub 化する
\Cake\Validation\Validation::uploadedFile が is_uploaded_file を使用しており、どうにも validation をテストで通過できなかったが、 stub 化することで対応できた。
このやり方は CakePHP 本体が同じことをやってる。
stub 用のファイルを用意して、テスト側で読み込めばOK。
// stub 側はこんな感じ
namespace Cake\Validation;
function is_uploaded_file($filename)
{
return file_exists($filename);
}
// テスト側で stub を読み込む require_once __DIR__ . DS . 'stubs.php';