Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing redirections CakePHP 2.0

I have been looking at some examples at the cookbook but i dont get it: http://book.cakephp.org/2.0/en/development/testing.html#a-more-complex-example

How can i test a redirection in a delete action like this one?

public function delete($id = null){         
        $this->Comment->id = $id;
        if (!$this->Comment->exists()) {
            throw new NotFoundException(__('Invalid comment'));
        }
        if ($this->Comment->delete()) {         
            $this->Session->setFlash(__('Comment deleted'));
            return $this->redirect(array('controller' => 'posts', 'action' => 'view', $idPost));
        }
        $this->Session->setFlash(__('Comment was not deleted'));
        return $this->redirect(array('controller' => 'posts', 'action' => 'view', $idPost));        
    }
}

The test stops after the redirect call, so it doesn't even print this echo:

public function testDelete(){       
    $result = $this->testAction("/comments/delete/1");
    echo "this is not printed";
    print_r($this->headers);        
}
like image 883
Alvaro Avatar asked Feb 21 '23 19:02

Alvaro


2 Answers

Testing your delete action should be relatively the same as testing any other action. Your test case might look something like this.

// notice it extends ControllerTestCase
class PostsControllerTest extends ControllerTestCase {

    function testDelete() {
      $this->testAction('/posts/delete/1');
      $results = $this->headers['Location'];
      // your OP code redirected them to a view, which I assume is wrong
      // because the item would be deleted
      $expected = '/posts/index';
      // check redirect
      $this->assertEquals($results, $expected);

      // check that it was deleted
      $this->Posts->Post->id = 1;
      $this->assertFalse($this->Posts->Post->exists());
    }

}

Of course, this just checks the obvious. You can also check the session and write a test that expects the exception. If it's still not reaching the end of the test case or continuing on, something else is going on.

You can generate easy mocks by using the generate method on ControllerTestCase.

function testDelete() {
  $Posts = $this->generate('Posts', array(
    'components' => array(
      'Email' => array('send'),
      'Session'
    )
  ));
  // set ControllerTestCase to use this mock
  $this->controller = $Posts;

  $this->testAction('/posts/some_action_that_sends_email');
}

The above would first generate a mock of the PostsController to use during testing. It also mocks the send() method on the EmailComponent, and the entire SessionComponent.

For more information on mocking: http://www.phpunit.de/manual/3.0/en/mock-objects.html

For more information on generate(): http://book.cakephp.org/2.0/en/development/testing.html#using-mocks-with-testaction

like image 61
jeremyharris Avatar answered Feb 23 '23 09:02

jeremyharris


Possible you have an error because $idPost is undefined.

I would write something like this:

public function delete($id = null){         
        $this->Comment->id = $id;
        if (!$this->Comment->exists()) {
            throw new NotFoundException(__('Invalid comment'));
        }
        if ($this->Comment->delete()) {         
            $this->Session->setFlash(__('Comment deleted'));
        } else {
            $this->Session->setFlash(__('Comment was not deleted'));
        }
        $this->redirect(array('controller' => 'posts', 'action' => 'view', $id));        
    }
}

And test it's like this:

public function testDeleteWithSuccess() {
        $Controller = $this->generate('Comments', array(
            'components' => array(
                'Session'
            ),
            'models' => array(
                'Comment' => array('exists')
            )
        ));

        $Controller->Comment->expects($this->once())
            ->method('exists')
            ->will($this->returnValue(true));

        $Controller->Session->expects($this->once())
            ->method('setFlash')
            ->with('Comment deleted');

        $this->testAction("/comments/delete/ID");

        $this->assertEquals($this->headers['Location'], 'http://'. $_SERVER['HTTP_HOST'] . '/posts/view/ID');
    }
like image 20
Andrew Kulakov Avatar answered Feb 23 '23 10:02

Andrew Kulakov