2011-11-21 15 views
5

Próbuję przetestować działanie kontrolera, który umożliwia edycję profili użytkowników. Między innymi chcę przetestować, że każdy zalogowany użytkownik może edytować tylko swój profil, a nie inny. W przypadku zerwania tego ograniczenia akcja musi przekierować na wcześniej zdefiniowaną stronę główną.Napisz do kontrolera, który używa AuthComponent w CakePHP 2

Przy tym scenariuszu, mam urządzenie, które tworzy użytkownika o ID = 1. Tak myślałem na testowaniu ograniczenie w ten sposób:

$data = $this->Users->User->read(null, 1); 
$this->Users->Auth->login($data); 
$this->testAction('/users/edit/2', array('method' => 'get')); 
$url = parse_url($this->headers['Location']); 
$this->assertEquals($url['path'], '/homepage'); 

Test przechodzi tego dochodzić. Więc następnym krokiem jest sprawdzenie, czy wykonanie '/users/edit/1', który ma identyfikator zalogowanego użytkownika, pokazuje postać:

$this->testAction('/users/edit/1', array('method' => 'get', 'return' => 'vars')); 
$matcher = array( 
    'tag' => 'form', 
    'ancestor' => array('tag' => 'div'), 
    'descendant' => array('tag' => 'fieldset'), 
); 
$this->assertTag($matcher, $this->vars['content_for_layout'], 'The edition form was not found'); 

Jednak to assert kończy się niepowodzeniem. Po kopania wokół z debug() Znalazłem że $this->Auth->user() zwraca całą informację ale $this->Auth->user('id') powraca null. Ponieważ używam tego ostatniego w porównaniu w akcji, wartość ta jest fałszywa i powoduje niepowodzenie testu .

Ciekawostką jest to, że dzieje się podczas testowania, ale nie podczas wykonywania działań w przeglądarce. Jaki jest więc właściwy sposób testowania tej akcji?

Dzięki!

Odpowiedz

5

Rzeczywista prawidłowa odpowiedź powinna być za pomocą makiety obiektów zamiast faktycznie zalogowaniu użytkownika w ręcznie:

$this->controller = $this->generate('Users', array(
    'components' => array('Auth' => array('user')) //We mock the Auth Component here 
)); 
$this->controller->Auth->staticExpects($this->once())->method('user') //The method user() 
    ->with('id') //Will be called with first param 'id' 
    ->will($this->returnValue(2)) //And will return something for me 
$this->testAction('/users/edit/2', array('method' => 'get')); 

Korzystanie mocks jest najbardziej prosty sposób przetestować kontroler, a także najbardziej elastyczny jeden

Aktualizacja 11 marca 2015

Można też kpić wszystkie metody AuthComponent

$this->controller = $this->generate('Users', array(
    'components' => array('Auth') // Mock all Auth methods 
)); 
+0

Jaki jest sens korzystania z 'ControllerTestCase', jeśli musisz mimo to używać' generate() '? – elitalon

+0

generate() jest dostępny tylko w ControllerTestCase i jest udostępniany w celu ułatwienia testAction(), np. Możliwość udawania metod kontrolera, komponentów, modeli itp. Jeśli nie wywołasz samodzielnie funkcji generate(), to testAction () zrobi to wewnętrznie dla ciebie z domyślnymi ustawieniami CakePHP (kpiąc z funkcji _stop() i przekierowania()) –

+0

Myślałem, że 'generate()' faktycznie zrobił coś innego. Dlatego ciągle zastanawiałem się, dlaczego go użyć, jeśli 'ControllerTestCase' dostarczył mi domyślną konfigurację. Spróbuję twojej odpowiedzi i dam ci znać :) – elitalon

0

Zamiast:

$this->Auth->user('id') 

Spróbuj jeden z nich:

$this->Auth->data['User']['id'] 
$this->Session->read('Auth.User.id') 
+0

To również nie działa. Czy te metody nie mają być równoważne? – elitalon

0

Ustaw je tak:

$this->Users->Session->write('Auth.User', 
    array('id' => 1,'and_other_fields_you_need' => 'whatever') 
); 
0

Mark Story daje mi answer in a CakePHP ticket. Zasadniczo mam do logowania użytkownika, jak poniżej:

$data = $this->Users->User->read(null, 1); 
$this->Users->Auth->login($data['User']); 

zamiast

$data = $this->Users->User->read(null, 1); 
$this->Users->Auth->login($data); 
1

Lubię Jose's answer, ale w obliczu podobnej sytuacji chcę używać rzeczywistego AuthComponent oraz Sesja stworzyć test, który da mi pewność siebie.

Używam uwierzytelniania opartego Controller, co oznacza, że ​​każdy kontroler w moim app musi dostarczyć własną isAuthorized() zwrotnego. Chcę przetestować MyController :: isAuthorized(). Wydaje się zbyt łatwe uzyskanie testu do przejścia przy użyciu mocks.

Zamiast więc użyć TestCase :: generate() do stworzenia pozornego kontrolera z fałszywymi komponentami, poszedłem za znakomitym artykułem Mark Story o numerze Testing CakePHP Controllers the hard way i dostarczyłem swój własny fałszywy kontroler, który loguje użytkownika z prawdziwym AuthComponent CakePHP.

Oto my work. Zobacz metodę testIsAuthorized() i defekt klasy dla MockAnnouncementsController u góry.

Wydaje mi się, że framework testujący CakePHP zakłada testowanie kontrolerów tylko za pomocą metody requestAction(). Nie został zaprojektowany w celu ułatwienia bezpośredniego testowania jednostkowego implementacji wywołań zwrotnych, takich jak Controller :: isAuthorized() w kontrolerze, bez kpienia z AuthComponent i być może innych komponentów, a to dałoby mi mniej pewności co do testu tej konkretnej metody. Niemniej jednak myślę, że jest to ważny przypadek użycia dla testowania jednostkowego części kontrolera, które nie są działaniami (np. "Indeks", "widok"), ale nie można ich delegować do komponentu, ponieważ muszą one być wywoływane przez podstawowe ramy . Nadal myślę o tym, jak mogę go streścić, aby był dostępny dla każdego kontrolera.

Powiązane problemy