Domanda

Voglio testare un pezzo di codice che utilizza la rete (la classe NSURLConnection , per essere specifici). Il codice (chiamiamolo NetworkManager ) è un po 'così:

- (id) buildConnection
{
    // some more code and then:
    return [NSURLConnection …];
}

- (void) startNetworkSync
{
    id connection = [self buildConnection];
    //…
}

Nel test unitario vorrei sbarazzarmi della rete, ad es. sostituire l'oggetto NSURLConnection con un mock. Come posso farlo?

Ho provato a creare una simulazione parziale del NetworkManager che avrebbe sostituito il metodo buildConnection con uno stub. Il problema è che le derisioni parziali fatte da OCMock bloccano solo i messaggi provenienti dal mondo esterno - l'invio di buildConnection da startNetworkSync invoca il metodo originale, non lo stub.

Ho anche provato a patchare la classe NetworkManager tramite una categoria. Funziona, posso facilmente sostituire il metodo buildConnection con un altro codice e sostituire il vero NSURLConnection con uno stub. Il problema è che non ho trovato un modo semplice per ottenere la connessione testata nel test: la connessione è una parte privata del NetworkManager .

Quindi potrei sottoclassare NetworkManager , sovrascrivere il metodo buildConnection e aggiungere una variabile di istanza più un accessor per la connessione creata. Questo sembra molto codice, tuttavia.

Come lo risolveresti? Sto cercando una soluzione che mantenga pulito il design della classe NetworkManager e non richieda molta magia né molto codice nel test.

È stato utile?

Soluzione

Questo è il tipo di cosa che l'iniezione di dipendenza è progettata per risolvere; se si utilizza startNetworkSyncWithConnection: (NSURLConnection *) invece è possibile testare facilmente il metodo con una connessione fittizia. Se non desideri modificare l'API per i tuoi clienti, potresti persino mantenere startNetworkSync come wrapper che non fa altro che chiamare quel nuovo metodo con [self buildConnection] come argomento.

Altri suggerimenti

Ho modificato OCMock per supportare simulazioni parziali reali, consultare il repo su GitHub .

Un'altra soluzione che ho usato di recente è quella di astrarre completamente l'interfaccia di rete. Se la classe necessita di alcuni dati dalla rete, probabilmente interagisce con alcuni servizi server che possono essere esplicitamente modellati come protocollo:

@protocol SomeNetworkService
- (NSArray*) allAvailableFoos;
- (void) insertNewFoo: (Foo*) foo;
@end

E poi avrai una vera implementazione HTTP e una di prova. Ciò significa più lavoro, ma anche una migliore testabilità. I test sono meno fragili e molto più convenienti, poiché il livello della rete di test può fare qualsiasi cosa tu abbia bisogno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top