我可以使用CakePHP 1.3&amp ;;在控制器中进行模拟redirect()结束测试吗? SimpleTest的?

时间:2012-02-14 18:58:16

标签: cakephp testing mocking cakephp-1.3 simpletest

我正在关注Mark Story的“Testing CakePHP controllers - Mock Objects edition”来测试一些具有重定向的控制器操作。我目前正在简单测试中模拟redirect()方法。我想重构一些代码,如下所示:

if (!$this->Model->someGuardCondition($id)){
  $this->redirect($this->referer());
}

if ($this->Model->save($this->data)){
  $this->redirect(array('controller' => 'controllerName', 'action' => 'actionName', $id));
}

问题是,如果第一个条件为真,那么我不希望测试执行第二个条件,因为这是它在生产中的工作方式。有没有办法在调用redirect()时终止测试而不会杀死整个测试套件?我知道我可以在每次重定向后放置一个return语句,但我宁愿不修改代码只是为了让测试行为正确。我应该坚持使用一堆丑陋的嵌套if / else语句吗?

编辑20120215 我将尝试使我的示例代码更完整,以证明问题:

some_controller.php:

class SomeController extends AppController
  function some_action($id) {
    if (!$this->Model->hasAuthorityToDoThis($id)){
      $this->Session->setFlash(__('The id is invalid for some reason'));
      $this->redirect($this->referer());
    }

   if ($this->Model->save($this->data)){
      $this->Session->setFlash(__('Save successful'));
      $this->redirect(array('controller' => 'controllerName', 'action' => 'actionName', $id));
   }
  }
}

some_controller_test.php:

class SomeControllerTestCase extends AppCakeTestCase {
  function testSomeAction() {
    $this->SomeController->Session = new MockSessionComponent();
    $this->SomeController->Session->expectOnce('setFlash');
    $this->SomeController->some_action('some-invalid-id');  // Note this is an invalid ID.

  }
}

因此,您可以从上面看到,我正在使用无效ID测试操作。这意味着第一个条件将通过。它会将flash消息设置为“由于某种原因id无效”并重定向到referer。在CakePHP重定向将调用重定向时退出脚本,因此代码永远不会实际进入模型 - > save()。但是,如果我在测试中模拟出redirect(),那么该方法基本上只返回而没有任何效果,并且控制器继续运行超过它应该的点。这很好,因为它不会中止测试套件,但它很糟糕,因为它实际上并不反映实际代码的行为。

说保存$ this->数据的调用很好。然后第一和第二条件都将通过。这将导致测试失败,因为您应该只设置一次Flash消息。

我猜测没有办法轻松编写这样的代码,只需坚持使用嵌套的if / else块就更好了。我只是想减少圈复杂度。

2 个答案:

答案 0 :(得分:0)

嵌套测试:

while (!$complete) {
   if (!$this->Model->someGuardCondition($id)){
      $this->redirect($this->referer());
      $complete = 1;
      continue;
   }

   if ($this->Model->save($this->data)){
      $this->redirect(array('controller' => 'controllerName', 'action' => 'actionName', $id));
      $complete = 1;
      continue;
   }
}

或者您可以使用if else语句:

if (!$this->Model->someGuardCondition($id)){
  $this->redirect($this->referer());
} elseif($this->Model->save($this->data)){
  $this->redirect(array('controller' => 'controllerName', 'action' => 'actionName', $id));
} else {
  return;
}

将每个测试移动到不同的方法,以便可以单独调用它们。

答案 1 :(得分:0)

只需使用return:

$this->redirect($this->referer());
return;

这样,您的控制器操作将在重定向后结束,与复杂的if/else等相比,它的代码更改要少得多。