views:

965

answers:

3

How can one best test a controller action which receives a file upload using Zend_Test_PHPUnit_ControllerTestCase?

Ideally, $this->getRequest()->setPost() would take a filename in the data array, but this does not seem to be supported.

I would be willing at this stage to bootstrap/run my application on the command line and create a request object to pass to the front controller. This would bypass Zend_Test_PHPUnit_ControllerTestCase, but I could subsequently check that the file was uploaded properly through a subsequent $this->dispatch('/some/url') in the ControllerTestCase. However, I am also stumped as to how to get a file into the request object using this method.

The only thing I can think to try right now is to bring up an HTTP server via the command line which points to the app (APPLICATION_ENV='testing') and do a file upload via Zend's Http Client or CURL or something. That doesn't strike me as very elegant.

Anyone else had to deal with this issue?

Thanks!

+2  A: 

I would recommend taking a look at the unit tests from the Zend_File_Transfer component. They will be able to offer some insight into this.

Basically, you can manipulate the $_FILES superglobal directly in the setUp() of your unit tests. Next, use mock objects for any external sort of service, otherwise you're not truly unit testing, but integration testing.

I would not worry about testing the actual process of uploading the file. That's the realm of the webserver and the language; what is important is you properly test what you do with a (or no) received file.

But, this all depends on how you are handling your file uploads right now. If you provided some more details on how you handle your file uploads, I may be able to offer more suggestions.

jason
Thanks for the pointer!The code is nothing special, controller action instantiates a form, checks if the request is a POST or not, if it is: do something with the file and put the other fields into the database, otherwise return the view with the form.Normally ControllerTestCase works quite well for testing this kind of controller code, but it just didn't have a mechanism for dealing with the file. I'll try this $_FILES idea.I'd love to see an example in a controller code test situation, if anyone's got an example to share!
A: 

I've a similar question, here's a code snippet:

class ProfileController extends Zend_Controller_Action {

private function getUploadAvatarForm()
{
    $form = new Zend_Form;
    $form->setAttrib('enctype', 'multipart/form-data');
    $form->setAction($this->view->baseUrl('/profile/upload-avatar'))
         ->setName('uploadAvatarForm')
         ->setMethod('POST');

    $element = new Zend_Form_Element_File('avatar');
    $element->setLabel('Upload an image:')
            ->addFilter('Rename',
                array('target' => '/path/toimages/directory/' . $this->userId . '.png',
                      'overwrite' => true)
            );

    $element->addValidator('Count', false, 1);
    $element->addValidator('Size', false, 102400);
    $element->addValidator('Extension', false, 'png');
    $form->addElement($element, 'avatar')
         ->addElement('submit', 'submit_upload', array('label' => 'upload'));
    return $form;
} 

public function uploadAvatarAction()
{
    $form = $this->getUploadAvatarForm();
    $this->view->form = $form;
    if (!$this->getRequest()->isPost() || !$form->isValid($_POST)) {
        return;
    }                
    if (!$form->avatar->receive()) {
        ... error...
    }
    ... ok ...
}

... }

The question is: part of bussiness logic is placed into Rename filter. In my vision it worth it, but may be I'm wrong.

I', trying to test it:

public function testUploadFile()
{
    $this->_doLogin('user', 'password');
    $this->getRequest()
         ->setMethod('POST'));
    $this->mockFileUpload();

    $this->dispatch('profile/upload-avatar');
    var_dump($this->getResponse()->getBody());
}

private function mockFileUpload()
{
    $_FILES = array(
        'avatar' => array(
            'name' => 'test.png',
            'type' => 'image/png',
            'tmp_name' => '/tmp/test.png',
            'error' => 0,
            'size' => 10127));
}

but got:

The file 'avatar' was illegal uploaded, possible attack

Could you please suggest me how to test this situation?

Alexey
Please ask a new question, rather than posting this as an "answer"
jason
A: 

To find the answer to Alexey's post, go here.

mbelanger