CakePHP / phpunit:如何模拟文件上传

CakePHP / phpunit : how to mock a file upload

我正在尝试为一个端点编写测试,该端点需要一个带有附加 CSV 文件的 post 请求。我知道像这样模拟 post 请求:

$this->post('/foo/bar');

但我不知道如何添加文件数据。我尝试手动设置 $_FILES 数组,但没有成功...

$_FILES = [
        'csvfile' => [
            'tmp_name' => '/home/path/to/tests/Fixture/csv/test.csv',
            'name' => 'test.csv',
            'type' => 'text/csv',
            'size' => 335057,
            'error' => 0,
        ],
];
$this->post('/foo/bar');

正确的做法是什么?

据我所知,CakePHP 神奇地结合了 $_FILES$_POST 等内容,因此我们可以从 $this->request->data[...] 访问每个内容。您可以使用可选的第二个参数将信息传递给该数据数组:

$data = [
        'csvfile' => [
            'tmp_name' => '/home/path/to/tests/Fixture/csv/test.csv',
            'name' => 'test.csv',
            'type' => 'text/csv',
            'size' => 45,
            'error' => 0,
        ],
];
$this->post('/foo/bar', $data);

模拟核心 PHP 函数有点棘手。

我猜你的帖子模型中有类似的东西。

public function processFile($file)
{
    if (is_uploaded_file($file)) {
        //process the file
        return true;
    }
    return false;
}

而你有这样一个相应的测试。

public function testProcessFile()
{
    $actual = $this->Posts->processFile('noFile');
    $this->assertTrue($actual);
}

由于您在测试过程中没有上传任何东西,所以测试总是会失败。

您应该在 PostsTableTest.php 的开头添加第二个命名空间,即使在单个文件中包含更多命名空间也是一种不好的做法。

<?php
namespace {
    // This allows us to configure the behavior of the "global mock"
    // by changing its value you switch between the core PHP function and 
    // your implementation
    $mockIsUploadedFile = false;
}

比起你的原始命名空间声明,你应该使用大括号格式。

namespace App\Model\Table {

并且可以添加PHP要覆盖的核心方法

function is_uploaded_file()
{
    global $mockIsUploadedFile;
    if ($mockIsUploadedFile === true) {
        return true;
    } else {
        return call_user_func_array('\is_uploaded_file',func_get_args());
    }
}

//other model methods

}  //this closes the second namespace declaration

关于 CakePHP 单元测试的更多信息:http://www.apress.com/9781484212134