2013-12-16 10 views
8

Sto esaminando un'applicazione e aggiungendo i test di unità. L'applicazione è scritta usando gli storyboard e supporta iOS 6.1 e versioni successive.Test se viene eseguito performSegueWithIdentifier all'interno di un metodo di visualizzazione controller

Sono stato in grado di testare tutti i soliti metodi di restituzione senza problemi. Tuttavia Attualmente sto perplesso con una certa prova che voglio realizzare:

In sostanza ho un metodo, consente di chiamare doLogin:

- (IBAction)doLogin:(UIButton *)sender { 

// Some logic here 

if (//certain criteria to meet) { 
    variable = x; // important variable set here 
    [self performSegueWithIdentifier:@"memorableWord" sender:sender]; 
} else { 
    // handler error here 
} 

Quindi voglio provare che o la segue è chiamato e che il variabile è impostata, o che il controller di visualizzazione MemorableWord è caricato e le variabili in là sono corrette. La variabile impostata qui nel metodo doLogin viene passata al controller della vista di destinazione di memorableWord segues nel metodo prepareForSegue.

Ho OCMock configurato e funzionante, e sto anche utilizzando XCTest come framework di test delle mie unità. Qualcuno è stato in grado di produrre un test unitario per coprire una situazione del genere?

Sembra che Google e SO siano piuttosto spogli per quanto riguarda le informazioni in quest'area. Un sacco di esempi su semplici test di base che sono piuttosto irrilevanti per la realtà più complessa dei test di iOS.

risposta

4

Sei sulla strada giusta, il test vuole verificare che:

  1. Quando il pulsante di accesso è sfruttato doLogin viene chiamato con il loginButton come mittente
  2. Se alcuni criteri è SI, chiamata performSegue

Quindi si dovrebbe effettivamente innescare il pieno flusso dal pulsante di accesso fino a performSegue:

- (void)testLogin { 
    LoginViewController *loginViewController = ...; 
    id loginMock = [OCMockObject partialMockForObject:loginViewController]; 

    //here the expect call has the advantage of swallowing performSegueWithIdentifier, you can use forwardToRealObject to get it to go all the way through if necessary 
    [[loginMock expect] performSegueWithIdentifier:@"memorableWord" sender:loginViewController.loginButton]; 

    //you also expect this action to be called 
    [[loginMock expect] doLogin:loginViewController.loginButton]; 

    //mocking out the criteria to get through the if statement can happen on the partial mock as well 
    BOOL doSegue = YES; 
    [[[loginMock expect] andReturnValue:OCMOCK_VALUE(doSegue)] criteria]; 

    [loginViewController.loginButton sendActionsForControlEvents:UIControlEventTouchUpInside]; 

    [loginMock verify]; [loginMock stopMocking]; 
} 

Avrai bisogno di implementare una proprietà per "criteri" in modo che ci sia un getter che puoi prendere in giro usando 'expect'.

È importante rendersi conto che 'expect' eseguirà solo una chiamata al getter, le chiamate successive non riusciranno con "Metodo invocato richiamato ...". Puoi usare "stub" per deriderlo per tutte le chiamate, ma questo significa che restituirà sempre lo stesso valore.

2

IMHO sembra essere uno scenario di test con not properly stato impostato.

Con unit test si deve solo test units (metodi per esempio singoli) della vostra applicazione. Queste unità devono essere independent da tutte le altre parti dell'applicazione. Questo ti garantirà che una singola funzione viene testata correttamente senza effetti collaterali. BTW: OCMock è un ottimo strumento per "deridere" tutte le parti che non si desidera testare e quindi creare effetti collaterali.

In generale il test sembra essere più simile a un test di integrazione

IT is the phase of software testing, in which individual software modules are combined and tested as a group.

Allora, cosa dovrei fare nel tuo caso:

vorrei neanche definire un test di integrazione, dove avrei correttamente testare tutte le parti del mio punto di vista e quindi indirettamente testare le mie vista controllori. Date un'occhiata a un buon quadro di prova per questo tipo di scenario - KIF

o avrei eseguire unit test singoli sui metodi 'doLogin' così come metodo per il calcolo dei criteri all'interno del vostro if. Tutte le dipendenze devono essere presi in giro fuori il che significa che all'interno della vostra prova doLogin, si dovrebbe anche prendere in giro il metodo criteri ...

+0

Grazie, ma questo è esattamente quello che sto cercando di fare. Sto provando a testare il metodo doLogin da solo e senza dipendenza da altro. per esempio, come uno dei miei test, voglio assicurarmi che il metodo chiamerà effettivamente performSegueWithIdentifier quando i criteri sono soddisfatti. Verificherò anche che l'errore venga gestito correttamente quando non lo è. Il mio problema è scoprire o meno il performSegueWithIdentifier chiamato o no. Qualche idea su questo? – Rob

+0

+1 per la spiegazione decente della differenza tra IT e UT, sono sicuro che gli utenti che hanno meno familiarità con il concetto di questo troveranno utile! :) – Rob

+1

OCMock ha metodi come verificare o rifiutare esattamente per questo tipo di scopo. Con la verifica è possibile assicurarsi che sia stato chiamato un metodo e tramite rifiuto si è certi che un metodo NON sia stato chiamato. Tieni presente che nel tuo caso potresti aver bisogno di usare un simulato parziale e che l'uso di molti banali parziali potrebbe essere segno di una cattiva progettazione delle applicazioni – Alexander

2

Quindi l'unico modo che posso vedere per me di test di unità è usare mock parziali:

- (void)testExample 
{ 
    id loginMock = [OCMockObject partialMockForObject:self.controller]; 

    [[loginMock expect] performSegueWithIdentifier:@"memorableWord" sender:[OCMArg any]]; 

    [loginMock performSelectorOnMainThread:@selector(loginButton:) withObject:self.controller.loginButton waitUntilDone:YES]; 

    [loginMock verify]; 
} 

Ovviamente questo è solo un esempio del test e non è in realtà il test che sto eseguendo, ma si spera che dimostri il modo in cui devo testare questo metodo nel mio controller di visualizzazione. Come puoi vedere, se lo performSegueWithIdentifier non viene chiamato, la verifica provoca il fallimento del test.

1

Dai a OCMock una lettura, ho appena acquistato un libro da Amazon su Unit Testing iOS ed è veramente buono da leggere. Sto cercando anche un libro TDD.

Problemi correlati