概要
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';