Alvaro
Alvaro

Reputation: 41605

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);        
}

Upvotes: 4

Views: 3512

Answers (4)

Uzzal Devkota
Uzzal Devkota

Reputation: 1

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));        
}

}

Plenix, Isn't that totally wrong? You are deleting a comment and passing the comment's id to the post's view controller ? So, you're viewing the post or the comment by doing so?? Any other suggestion ?

Upvotes: 0

Andrew Kulakov
Andrew Kulakov

Reputation: 2092

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');
    }

Upvotes: 1

jeremyharris
jeremyharris

Reputation: 7882

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

Upvotes: 7

BruneX
BruneX

Reputation: 588

The echo never be printed, your function "delete" always calls a redirect before ends.

Upvotes: 0

Related Questions