CakePHP 3.7 - 测试用例文件上传

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CakePHP 3.7 - 测试用例文件上传相关的知识,希望对你有一定的参考价值。

如何在Cakephp 3中使用控制器测试用例测试文件上传功能?

我一直遇到PHP认为文件实际上没有上传的问题。适用于浏览器测试的验证规则,但不适用于测试用例:

                ->add('file', [
                    'is_uploaded_file' => [
                        'rule' => ['uploadedFile', ['optional' => false]],
                        'message' => 'File is no valid uploaded file'
                   ],

我很快发现is_uploaded_filemove_uploaded_file不可能在单元测试中愚弄。

但是,关于这个的大多数主题都是旧的和/或没有具体的CakePHP,所以我想我会发布一个新的问题。

答案

您不一定需要修改验证规则,您可以做的是使用实现PsrHttpMessageUploadedFileInterface的对象。 CakePHP的默认上传文件验证支持此类对象。

CakePHP需要zendframework/zend-diactoros,所以你可以使用endDiactorosUploadedFile并在你的测试中做这样的事情:

$data = [
    // ...
    'file' => new endDiactorosUploadedFile([
        '/path/to/the/temporary/file/on/disk',
        1234, // filesize in bytes
        UPLOAD_ERR_OK, // upload (error) status
        'filename.jpg', // upload filename
        'image/jpeg' // upload mime type
    ])
];

uploadedFile规则会自动将此类对象视为上传文件。

当然,处理文件上传的代码也必须支持该接口,但它并不复杂,您只需要确保将常规文件上载数组转换为UploadedFileInterface实现,以便您的上传处理程序可以满足要求。

它当然可以在上传处理程序本身中完成,因此验证将使用常规文件上载数组以及UploadedFile对象。另一种方法是在创建实体时使用beforeMarshal处理程序/事件更早地转换它们,这有点像这样:

public function beforeMarshal(CakeEventEvent $event, ArrayObject $data, ArrayObject $options)
{
    $file = CakeUtilityHash::get($data, 'file');
    if ($file === null) {
        return;
    }

    if (!($file instanceof PsrHttpMessageUploadedFileInterface)) {
        $file = new endDiactorosUploadedFile(
            CakeUtilityHash::get($file, 'tmp_name'),
            CakeUtilityHash::get($file, 'size'),
            CakeUtilityHash::get($file, 'error'),
            CakeUtilityHash::get($file, 'name'),
            CakeUtilityHash::get($file, 'type')
        );
        $data['file'] = $file;
    }
}

如果您随后使用PsrHttpMessageUploadedFileInterface::moveTo()移动文件,它将在SAPI(基于浏览器)以及非SAPI(CLI)环境中工作:

try {
    $file->moveTo($targetPath);
} catch (Exception $exception) {
    $entity->setError(
        'file', [__('The file could not be moved to its destination.')]
    );
}

也可以看看

另一答案

我发布后几乎立刻就知道了。 该解决方案基于https://pierrerambaud.com/blog/php/2012-12-29-testing-upload-file-with-php

因此解决问题的唯一方法是覆盖内置函数:is_uploaded_filemove_uploaded_file

uploadedFile验证规则存在于CakeValidation内部,我在表事件中使用move函数,因此在AppModelTable中。

我在控制器测试用例的顶部添加了以下内容:

<?php

namespace CakeValidation;

function is_uploaded_file($filename)
{
    return true;
}

namespace AppModelTable;

function move_uploaded_file($filename, $destination)
{
    return copy($filename, $destination);
}

namespace AppTestTestCaseController;

use AppControllerCarsController;
use CakeTestSuiteIntegrationTestTrait;
use CakeTestSuiteTestCase;
use CakeCoreConfigure;

/**
 * AppControllerCarsController Test Case
 */
class CarsControllerTest extends BaseTestCase
{

    use IntegrationTestTrait;

    // ...

它的工作原理!

以上是关于CakePHP 3.7 - 测试用例文件上传的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Cakephp 的 Controller 第二个测试用例总是失败

Cakephp 3.7 hasOne字段数据不保存

CakePHP 3.7。*迁移:跳过或更改schema.lock文件生成路径

CakePHP 3.6 控制器集成测试 - 未发送 HTTP 请求

面试题:编写上传和下载文件测试用例

列出 CakePHP 文件上传错误代码