2012-02-14 4 views
0

리디렉션이있는 일부 컨트롤러 작업을 테스트하기 위해 Mark Story의 "Testing CakePHP controllers - Mock Objects edition"을 따르고 있습니다. 나는 현재 간단한 테스트에서 redirect() 메소드를 조롱하고있다. 나는 다음과 같이보고 몇 가지 코드를 리팩토링 원 :CakePHP 1.3 & Simpletest를 사용하여 컨트롤러에서 mock 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 문을 사용하는 것에 충실해야합니까?

EDIT 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로 작업을 테스트하고 있습니다. 이것은 첫 번째 조건이 통과 함을 의미합니다. 플래시 메시지를 '어떤 이유로 든 ID가 유효하지 않습니다'로 설정하고 리퍼러에게 리디렉션합니다. CakePHP에서 리디렉션을 호출 할 때 스크립트가 종료되므로 코드가 실제로 model-> save()를 수행하지 않습니다. 그러나 테스트에서 redirect()를 조롱하면 메서드는 본질적으로 아무런 효과도없이 반환되며 컨트롤러는 필요한 지점을지나 계속 실행됩니다. 이것은 테스트 스위트를 중단하지 않는다는 점에서 우수하지만 실제 코드의 실제를 반영하지 않기 때문에 좋지 않습니다.

$ this-> data를 저장하라는 호출이 좋다는 말. 그러면 첫 번째 조건과 두 번째 조건이 모두 통과합니다. 플래시 메시지가 한 번만 설정되어야하므로 테스트가 실패하게됩니다.

나는 이와 같은 코드를 쉽게 작성할 방법이 없다고 생각하며 중첩 된 if/else 블록을 고수하는 것이 좋습니다. 나는 단지 순환 복잡성을 줄이려고 노력했다.

+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 (!$this->Model->someGuardCondition($id)){ 
    $this->redirect($this->referer()); 
} elseif($this->Model->save($this->data)){ 
    $this->redirect(array('controller' => 'controllerName', 'action' => 'actionName', $id)); 
} else { 
    return; 
} 

광석은 다른 방법으로 각각의 테스트를 이동합니다.

0

그냥 반환 사용

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

이 방법은, 컨트롤러의 동작이 리디렉션 후 종료됩니다, 그리고 내가 질문을 다시 읽어하지만 이렇게 복잡한 if/else