FriendsOfCake / cakephp-upload

CakePHP: Handle file uploading sans ridiculous automagic
https://cakephp-upload.readthedocs.io/
MIT License
551 stars 255 forks source link

Mocking method in behavior #497

Closed kriskd closed 2 years ago

kriskd commented 5 years ago

I'm using version 3.8.1 of this plugin because my project is on Cake 3.4.14.

I'm having difficulty mocking a method in the behavior for my controller (integration test).

Here is how I'm adding the behavior to my Table Class:

$this->addBehavior('Josegonzalez/Upload.Upload', [
    'file' => [
        'path' => 'webroot{DS}img{DS}CampSessions{DS}Camps{DS}{field-value:camp}',
        'deleteCallback' => function ($path, $entity, $field, $settings) {
            return [
                $path . DS . $entity->{$field},
            ];
        },
        'keepFilesOnDelete' => false
    ],
]);

And my mock in my test is setup like this:

$Writer = $this->getMockBuilder('Josegonzalez\Upload\File\Writer\DefaultWriter')
    ->setMethods(['write'])
    ->disableOriginalConstructor()
    ->getMock();
$Writer->expects($this->any())
    ->method('write')
    ->will($this->returnValue([true]));
$Upload = $this->getMockBuilder('Josegonzalez\Upload\Model\Behavior\UploadBehavior')
    ->setMethods(['getWriter'])
    ->setConstructorArgs([$this->Images, [
        'file' => [
            'path' => 'webroot{DS}img{DS}CampSessions{DS}Camps{DS}{field-value:camp}',
            'deleteCallback' => function ($path, $entity, $field, $settings) {
                return [
                    $path . DS . $entity->{$field},
                ];
            },
            'keepFilesOnDelete' => false
        ],
    ]])
    ->getMock();
$Upload->expects($this->any())
    ->method('getWriter')
    ->will($this->returnValue($Writer));

$this->Images->behaviors()->set('Josegonzalez/Upload.Upload', $Upload);

The result is getWriter is not getting mocked as I would expect. The getWriter method is reached and obviously not returning my mocked $Writer.

However, if I make the key in my addBehavior options anything but file, then the mock works. So change it to:

$this->addBehavior('Josegonzalez/Upload.Upload', [
    'foo' => [
        'path' => 'webroot{DS}img{DS}CampSessions{DS}Camps{DS}{field-value:camp}',
        'deleteCallback' => function ($path, $entity, $field, $settings) {
            return [
                $path . DS . $entity->{$field},
            ];
        },
        'keepFilesOnDelete' => false
    ],
]);

The mock is now respected and the test passes but of course the upload won't work because the column name in my table is file, not foo.

Suggestions on what I may be doing wrong?

davidyell commented 5 years ago

I'd be tempted to mock the Writer and just put it into the class, rather than trying to overload the method return. If the getWriter() returns a Writer instance, I presume if you set a Mock into the class the method will return that anyway.