2011-11-21 12 views
5

sto cercando di testare un'azione di controllo che consente edizione di profili utente. Tra le altre cose voglio testare che ogni utente registrato possa modificare solo il proprio profilo e non quello degli altri. In caso di violazione di questa restrizione, l'azione deve reindirizzare a una pagina iniziale predefinita.scrivere per un controller che utilizza AuthComponent in CakePHP 2

Con questo scenario, ho un appuntamento fisso che crea un utente con ID = 1. Stavo pensando sul test del restrizione in questo modo:

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

Il test viene superato questo assert. Quindi il passo successivo è quello di verificare se l'esecuzione di '/users/edit/1', che ha l'ID dell'utente collegato, mostra la forma:

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

Tuttavia questa asserzione fallisce. Dopo aver scavato in giro con debug() ho trovato che $this->Auth->user() restituisce tutta l'informazione, ma $this->Auth->user('id') rendimenti null. Da quando uso quest'ultimo in un confronto all'interno dell'azione, valuta come falso e provoca la prova di sicuro.

La cosa curiosa è che accade durante il test, ma non quando si esegue l'azione in un browser. Quindi, qual è il modo corretto di testare questa azione?

Grazie!

risposta

5

La risposta effettiva corretta dovrebbe essere utilizzando oggetti mock in realtà invece di login dell'utente in modo manuale:

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

L'utilizzo di mock è il modo più semplice per testare un controller e anche il più flessibile

aggiornamento 11 Marzo 2015

Si può anche prendere in giro tutto il metodo di AuthComponent

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

Qual è il punto allora di usare 'ControllerTestCase' se devi usare' generate() 'comunque? – elitalon

+0

generate() è disponibile solo in ControllerTestCase ed è fornito per rendere più semplice testAction(), come essere in grado di simulare metodi, componenti, modelli di controller, ecc. Se non si chiama generate(), quindi testAction () lo farà internamente per te con i default di CakePHP (mocking the _stop() e la funzione redirect()) –

+0

Ho pensato che 'generate()' in realtà ha fatto qualcos'altro. Ecco perché ho continuato a pensare perché usarlo se "ControllerTestCase" mi ha fornito una configurazione predefinita. Proverò la tua risposta e ti faccio sapere :) – elitalon

0

Invece di:

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

provare uno di questi:

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

Non funziona neanche. Non sono questi metodi pensati per essere equivalenti? – elitalon

0

Set in questo modo:

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

Mark Story mi dà la answer in a CakePHP ticket. Fondamentalmente devo registrare l'utente in questo modo:

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

invece di

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

mi piace Jose's answer, ma di fronte a una situazione simile che voglio usare l'AuthComponent reale e di sessione per creare un test che mi darebbe sicurezza

Sto usando l'autenticazione Controller-based, il che significa che ogni controller nella mia app deve fornire il proprio isAuthorized() callback. Voglio testare MyController :: isAuthorized(). Sembra troppo facile ottenere un test per passare usando i mock.

Quindi, invece di usare TestCase :: generate() per creare un controller fittizio con componenti finti, ho seguito l'eccellente articolo di Mark Story Testing CakePHP Controllers the hard way e fornito il mio controller fittizio che registra un utente con il vero CakePHP AuthComponent.

Ecco il numero my work. Vedi il metodo testIsAuthorized() e la classe def per MockAnnouncementsController in alto.

Mi sembra che il framework di testing di CakePHP presupponga che si desidera testare i controller solo tramite requestAction(). Non è stato progettato per facilitare il collaudo diretto delle implementazioni di callback come Controller :: isAuthorized() all'interno di un controller senza il mocking di AuthComponent e forse di altri componenti, e questo mi darebbe meno fiducia nel test di quel particolare metodo. Tuttavia, penso che questo sia un caso d'uso valido per le parti di test unitari di un controller che non sono azioni (ad esempio "indice", "vista"), ma non può essere delegato a un componente perché devono essere richiamati dal framework principale . Sto ancora pensando a come potrei astrarlo per renderlo disponibile per qualsiasi controller.

Problemi correlati