Introduzione al test su iOS

Nessuno vuole spedire il software buggato. Garantire che si rilascia un'applicazione mobile della massima qualità richiede molto più di un processo di garanzia della qualità manuale basato sull'uomo. Nuovi dispositivi e sistemi operativi vengono rilasciati al pubblico ogni anno. Ciò significa che esiste una combinazione in continua espansione di dimensioni dello schermo e versioni del sistema operativo su cui è necessario testare l'applicazione mobile. Non solo sarebbe molto dispendioso in termini di tempo, ma il tentativo di testare la tua applicazione iOS con un test manuale trascura un intero pezzo del moderno processo di ingegneria del software, test di controllo automatico della qualità.

Nel mondo di oggi, ci sono molti strumenti disponibili che possono essere usati per testare automaticamente il software che scrivi. Alcuni di questi strumenti sono gestiti tramite un modello open source, ma esiste anche un set base fornito da Apple. Con ogni nuova versione dell'SDK iOS, Apple ha continuato a mostrare il proprio impegno nel migliorare gli strumenti disponibili per gli sviluppatori per testare il codice che scrivono. Per gli sviluppatori iOS che sono nuovi ai test automatici e interessati a iniziare, gli strumenti di Apple sono un buon punto di partenza.

1. Apple fornisce strumenti utili

Questo tutorial fornirà le istruzioni per l'utilizzo di uno strumento che Apple fornisce per i test automatizzati, XCTest. XCTest è il framework di test unitario di Apple. Il test unitario è il tipo di test automatizzato che verifica il codice al livello più basso. Scrivi codice Objective-C che chiama i metodi dal tuo codice di "produzione" e verifica che il codice sotto test faccia effettivamente ciò che è destinato a fare. Le variabili sono impostate correttamente? Il valore restituito è corretto?

I test scritti con il framework XCTest possono essere ripetutamente eseguiti contro il codice dell'applicazione per aiutarti a ottenere la certezza che stai creando un prodotto privo di bug in quel nuovo codice che le modifiche non stanno infrangendo la funzionalità esistente.
Per impostazione predefinita, ogni nuovo progetto Xcode viene creato con un buon punto di partenza per scrivere i test delle unità. Questo include tre cose:

  • un obiettivo separato per i tuoi test
  • un gruppo per le tue classi di test
  • un esempio di test


Analizziamo la struttura di un test dell'unità iOS. Un test unitario individuale è rappresentato come un singolo metodo all'interno di qualsiasi sottoclasse di XCTestCase dove ritorna il metodo vuoto, non accetta parametri e inizia con il nome del metodo test.

- (vuoto) testSomething 

Fortunatamente, Xcode semplifica la creazione di casi di test. Con i nuovi progetti Xcode, un caso di test iniziale viene creato per te in un gruppo di file separato il cui nome è suffisso dalla parola test.

2. Creazione del primo test dell'unità iOS

Ho creato un progetto di esempio che può essere utilizzato come riferimento per gli esempi forniti in questo tutorial. Scarica il progetto da GitHub e aprilo in Xcode.

Passaggio 1: creare la classe del caso di test

Nel progetto di esempio, è possibile trovare il gruppo di test nella cartella denominata JumblifyTests.

Per creare il tuo primo test case, fai clic con il pulsante destro del mouse sul gruppo di file, JumblifyTests, e selezionare Nuovo file. Scegliere Classe di casi di test dal iOS> Origine sezione e dare alla nuova sottoclasse un nome.

La tipica convenzione di denominazione è nominare il caso di test in modo tale che sia il nome della classe corrispondente sotto test, con suffisso test. Dal momento che testeremo il JumblifyViewController classe, nominare il XCTestCase sottoclasse JumblifyViewControllerTests.

Passaggio 2: rimuovere il codice Boilerplate

Nel nuovo di zecca XCTestCase sottoclasse, vedrai quattro metodi. Due di questi sono test stessi. Puoi identificare quali sono? Ricorda che i nomi dei metodi di prova iniziano con la parola "test".

Se non l'hai capito, i metodi di prova creati per impostazione predefinita sono testExample e testPerformanceExample.

Elimina entrambi i test, perché scriveremo il nostro da zero. Gli altri due metodi, impostare e demolire, sono sovrascritti dalla superclasse, XCTestCase. Sono unici in questo impostare e demolire vengono chiamati prima e dopo ogni metodo di prova viene invocato rispettivamente. Sono luoghi utili per centralizzare il codice che deve essere eseguito prima o dopo la chiamata di ogni metodo di prova. Attività come l'inizializzazione o la pulizia comuni vanno qui.

Passaggio 3: collega il test alla classe in prova

Importa il file di intestazione del file JumblifyViewController classe e aggiungere una proprietà di tipo JumblifyViewController al XCTestCase sottoclasse.

@property (nonatomic) JumblifyViewController * vcToTest;

Nel impostare metodo, inizializza la proprietà come mostrato di seguito.

- (vuoto) setUp [super setUp]; self.vcToTest = [[JumblifyViewController alloc] init]; 

Passaggio 4: scrivere un test

Ora stiamo andando a scrivere un test per testare il ReverseString: metodo del JumblifyViewController classe.

Creare un metodo di prova che utilizza l'istanza vcToTest oggetto di testare il ReverseString: metodo. In questo metodo di test, creiamo un NSString oggetto e passalo al controller della vista ReverseString: metodo. È convenzione comune dare al test un nome significativo per chiarire cosa sta testando il test.

- (void) testReverseString NSString * originalString = @ "himynameisandy"; NSString * reverseedString = [self.vcToTest reverseString: originalString]; 

A questo punto, non abbiamo ancora fatto nulla di utile, perché non abbiamo testato il ReverseString: metodo ancora. Quello che dobbiamo fare è confrontare l'output del ReverseString: metodo con ciò che ci aspettiamo che l'output sia.

Il XCTAssertEqualObjects la funzione fa parte del framework XCTest. Il framework XCTest fornisce molti altri metodi per fare asserzioni sullo stato dell'applicazione, come l'uguaglianza delle variabili oi risultati di espressioni booleane. In questo caso, abbiamo affermato che due oggetti devono essere uguali. Se lo sono, il test passa e se non lo sono, il test fallisce. Dai un'occhiata alla documentazione di Apple per un elenco completo di asserzioni fornite dal framework XCTest.

- (void) testReverseString NSString * originalString = @ "himynameisandy"; NSString * reverseedString = [self.vcToTest reverseString: originalString]; NSString * expectedReversedString = @ "ydnasiemanymih"; XCTAssertEqualObjects (expectedReversedString, reversedString, @ "La stringa invertita non corrisponde al contrario atteso");

Se provi a compilare il codice a questo punto, noterai un avviso quando tenti di chiamare ReverseString: dal caso di test. Il ReverseString: metodo è un metodo privato di JumblifyViewController classe. Ciò significa che altri oggetti non possono richiamare questo metodo poiché non è definito nel file di intestazione del file JumblifyViewController classe.

Mentre scrivere un codice testabile è un mantra seguito da molti sviluppatori, non vogliamo modificare inutilmente il nostro codice sotto test. Ma come chiamiamo il privato ReverseString: metodo del JumblifyViewController classe nei nostri test? Potremmo aggiungere una definizione pubblica di ReverseString: metodo per il file di intestazione del JumblifyViewController classe, ma che rompe il modello di incapsulamento.

Passaggio 5: aggiunta di una categoria privata

Una soluzione è aggiungere una categoria privata su JumblifyViewController classe per esporre il ReverseString: metodo. Aggiungiamo questa categoria al XCTestCase sottoclasse, il che significa che è disponibile solo in quella classe. Aggiungendo questa categoria, il test case verrà compilato senza avvertimenti o errori.

@interface JumblifyViewController (Test) - (NSString *) reverseString: (NSString *) stringToReverse; @fine

Passaggio 6: eseguire il test

Eseguiamo i nostri test per assicurarci che passino. Esistono diversi modi per eseguire i test unitari per un'applicazione iOS. Sono un drogato di tasti di scelta rapida, quindi la mia tecnica più utilizzata per eseguire i miei test di unità per la mia applicazione è premendo Comando-U. Questa scorciatoia da tastiera eseguirà tutti i test per la tua applicazione. Puoi anche eseguire la stessa azione selezionando Test dal Prodotto menu.

Man mano che la suite di test cresce, o se ti piace implementare lo sviluppo basato sui test, scoprirai che l'esecuzione della tua suite di test può richiedere troppo tempo. Oppure potrebbe ostacolare il tuo flusso di lavoro. Un comando molto utile, sepolto nel menu di Xcode, di cui mi sono innamorato Comando-Opzione-Control-U. Questa scorciatoia attiva un comando che esegue il test in cui si trova attualmente il cursore. Una volta che la suite di test è stata completata e finalizzata, è necessario eseguire sempre l'intera suite di test. Eseguire un test individuale è utile mentre stai scrivendo un nuovo test o quando esegui il debug di un test non funzionante.

Il comando per eseguire un test è completato da Comando-Opzione-Control-G, che ripassa l'ultimo test eseguito. Questa può essere l'intera suite di test o solo il test più recente su cui stai lavorando. È anche utile nel caso in cui ti sei allontanato da qualsiasi test a cui stai lavorando e sei ancora in fase di debug.

Passaggio 7: rivedere i risultati

Puoi vedere i risultati del test in un paio di punti. Uno di quei posti è il Test Navigator sulla destra.

Un'altra opzione è guardando la grondaia del Editor di sorgenti.

In uno di questi due punti, facendo clic sul diamante verde con il segno di spunta bianco, verrà rieseguito quel particolare test. Nel caso di un test fallito, vedrai un diamante rosso con una croce bianca al centro. Facendo clic sul pulsante verrà rieseguito anche quel particolare test.

3. Nuovo in Xcode 6

Xcode 6 ha introdotto due nuove entusiasmanti aggiunte ai test unitari su iOS e OS X, testando la funzionalità asincrona e misurando le prestazioni di una specifica parte di codice.

Test asincroni

Prima di Xcode 6, non c'era un buon modo per testare il codice asincrono. Se il test dell'unità ha chiamato un metodo che conteneva la logica asincrona, non è possibile verificare la logica asincrona. Il test sarebbe completato prima dell'esecuzione della logica asincrona nel metodo sotto test.

Per testare il codice asincrono, Apple ha introdotto un'API che consente agli sviluppatori di definire un'aspettativa che deve essere soddisfatta per il completamento del test. Il flusso è il seguente, definisce un'aspettativa, aspetta che l'aspettativa sia soddisfatta e soddisfa l'aspettativa quando il codice asincrono ha terminato l'esecuzione. Dai un'occhiata al seguente esempio per chiarimenti.

- (void) testDoSomethingThatTakesSomeTime XCTestExpectation * completionExpectation = [self expectationWithDescription: @ "Metodo lungo"]; [self.vcToTest doSomethingThatTakesSomeTimesWithCompletionBlock: ^ (risultato NSString *) XCTAssertEqualObjects (@ "risultato", risultato, @ "Risultato non corretto!"); [completionExpectation fulfill]; ]; [self waitForExpectationsWithTimeout: 5.0 handler: nil]; 

In questo esempio, stiamo testando il doSomethingThatTakesSomeTimesWithCompletionBlock metodo. Vogliamo determinare il successo o il fallimento del nostro test sul valore che viene restituito nel blocco di completamento chiamato dal metodo sotto test.

Per fare ciò, definiamo un'aspettativa all'inizio del metodo di prova. Alla fine del metodo di test, attendiamo che le aspettative siano soddisfatte. Come puoi vedere, possiamo anche passare un parametro di timeout.

L'effettiva asserzione del test viene effettuata all'interno del blocco di completamento del metodo in prova, nel quale soddisfiamo anche le aspettative che abbiamo definito in precedenza. Di conseguenza, quando viene eseguito il test, il test attende fino a quando l'aspettativa è soddisfatta o fallisce se il timeout scade e l'aspettativa non viene soddisfatta.

Test delle prestazioni

Un'altra aggiunta al test delle unità in Xcode 6 è la capacità di misurare le prestazioni di un pezzo di codice. Ciò consente agli sviluppatori di ottenere informazioni dettagliate sulle informazioni di temporizzazione specifiche del codice che viene testato.

Con il test delle prestazioni, puoi rispondere alla domanda "Qual è il tempo medio di esecuzione per questo pezzo di codice?" Se esiste una sezione particolarmente sensibile alle modifiche in termini di tempo necessario per l'esecuzione, è possibile utilizzare il test delle prestazioni per misurare la quantità di tempo necessaria per l'esecuzione.

È anche possibile definire un tempo di esecuzione della linea di base. Ciò significa che se il codice che viene testato devia in modo significativo da tale linea di base, il test fallisce. Xcode eseguirà ripetutamente il codice che viene testato e ne misura il tempo di esecuzione. Per misurare le prestazioni di un pezzo di codice, utilizzare il measureBlock: API come mostrato di seguito.

- (void) testPerformanceReverseString NSString * originalString = @ "himynameisandy"; [self measureBlock: ^ [self.vcToTest reverseString: originalString]; ]; 

Fai clic sul messaggio informativo che appare.

Imposta o modifica il tempo di esecuzione della linea di base per il test delle prestazioni.

Conclusione

In questo tutorial, hai imparato come usare Xcode per creare test unitari per verificare un'applicazione iOS in modo programmatico e automatico. Fare un tentativo, su un codice esistente o qualcosa di nuovo di zecca. Indipendentemente dal fatto che tu ti impegni a fondo per testare le unità o aggiungere un paio di test qua e là, stai solo aggiungendo valore al tuo progetto attraverso la scrittura di un software più fortemente verificato che è meno incline a rompere con le modifiche future. Il test delle unità è solo l'inizio di test automatici del software. Esistono diversi livelli aggiuntivi di test che è possibile aggiungere a un'applicazione iOS.