2014-11-27 22 views
9

Il test delle unità è solo qualcosa che non riesco mai a capire, ma posso capire perché è importante e può essere un enorme risparmio di tempo (se sai cosa sei tu sta facendo). Spero che qualcuno possa indicarmi la giusta direzione.Come testare un UIViewController - TDD/BDD

Ho il seguente UIViewController

QBElectricityBaseVC.h

@interface QBElectricityBaseVC : QBStateVC 

@property (nonatomic, strong) QBElectricityUsage *electricityUsage; 
@property (nonatomic, assign) CGFloat tabBarHeight; 

- (void)updateElectricityUsage; 

@end 

QBElectricityBaseVC.m

@implementation QBElectricityBaseVC 

- (instancetype)init 
{ 
    self = [super init]; 
    if (self) { 
     self.tabBarItem = [[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"electricity_title", nil) image:nil tag:0]; 
    } 
    return self; 
} 

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 

    [self.notificationCenter addObserver:self selector:@selector(updateElectricityUsage) 
               name:kUpdatedElectricityUsageKey object:nil]; 
} 

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 

    [self.notificationCenter removeObserver:self]; 
} 

- (void)updateElectricityUsage 
{ 
    self.electricityUsage = [self.stateManager electricityUsage]; 
} 

- (CGFloat)tabBarHeight 
{ 
    return self.tabBarController.tabBar.frame.size.height; 
} 

@end 

Cosa devo sottoporre a test?

  • Un osservatore per kUpdatedElectricityUsageKey si aggiunge
  • self.electricityUsage diventa un'istanza di QBElectricityUsage
  • Un tabBarHeight viene restituito
  • Un osservatore per kUpdatedElectricityUsageKey viene rimosso

mi sto perdendo qualcosa che dovrei testare o testare qualcosa che davvero non dovrei?

Come si esegue il test?

Quindi sto cercando di farlo utilizzando Specta e Expexta. Se devo prendere in giro qualcosa, utilizzerei OCMockito.

Non so davvero come testare l'osservatore aggiunto/rimosso. Vedo il seguente nella documentazione Expexta ma non è sicuro se il suo rilevante/come usarlo:

expect(^{ /* code */ }).to.notify(@"NotificationName"); passes if a given block of code generates an NSNotification named NotificationName. 

expect(^{ /* code */ }).to.notify(notification); passes if a given block of code generates an NSNotification equal to the passed notification. 

Per verificare che self.electricityUsage diventa un'istanza di QBElectricityUsage ho potuto creare una categoria che ha un metodo che fa solo finta la notifica licenziato e chiama il metodo updateElectricityUsage ma è questo il modo migliore?

E per quanto riguarda lo tabBarHeight, dovrei semplicemente provare che restituisce un valore valido CGFloat e non preoccuparti di quale sia il valore?


UPDATE

ho cambiato il mio metodo viewWillAppear a guardare come di seguito:

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
    [self addNotificationObservers]; 
} 

- (void)addNotificationObservers 
{ 
    [self.notificationCenter addObserver:self selector:@selector(updateElectricityUsage) 
            name:kUpdatedElectricityUsageKey object:nil]; 
} 

E poi ho creato il seguente test:

#import "Specs.h" 

#import "QBElectricityBaseVC.h" 
#import "ElectricityConstants.h" 

SpecBegin(QBElectricityBaseVCSpec) 

    describe(@"QBElectricityBaseVC", ^{ 
     __block QBElectricityBaseVC *electricityBaseVC; 
     __block NSNotificationCenter *mockNotificationCenter; 

     beforeEach(^{ 
      electricityBaseVC = [QBElectricityBaseVC new]; 
      mockNotificationCenter = mock([NSNotificationCenter class]); 
      electricityBaseVC.notificationCenter = mockNotificationCenter; 
     }); 

     afterEach(^{ 
      electricityBaseVC = nil; 
      mockNotificationCenter = nil; 
     }); 

     it(@"should have a notification observer for updated electricity usage", ^{ 
      [electricityBaseVC addNotificationObservers]; 
      [verify(mockNotificationCenter) addObserver:electricityBaseVC selector:@selector(updateElectricityUsage) 
               name:kUpdatedElectricityUsageKey object:nil]; 
     }); 
    }); 

SpecEnd 

Questo test ora passa ma è questo il modo corretto/migliore per prova questo?

+0

Ho le stesse identiche domande - vorrei che ci fosse più documentazione là fuori. Inoltre, perché non è andato con XCTest? – dccarmo

risposta

2

Seguo 2 pratiche per testare i pezzi di un UIViewController.

  1. MVVM: con uno schema MVVM è possibile testare facilmente il contenuto delle visualizzazioni nei test di unità per le classi ViewModel. Ciò mantiene anche la logica del ViewController molto leggera, quindi non è necessario scrivere tanti test dell'interfaccia utente per coprire tutti questi scenari.
  2. KIF - quindi per il test dell'interfaccia utente utilizzo KIF perché il suo attore di test consente di gestire asincroni e visualizzare i ritardi di caricamento. Con KIF posso inviare una notifica dal mio codice e il mio test attenderà di vedere gli effetti del mio gestore di notifiche nella vista.

Tra questi 2 sistemi sono in grado di testare l'unità praticamente tutto e quindi molto facilmente scrivere i test dell'interfaccia utente per coprire le parti finali.

Inoltre, nota rapida sul codice: non aggiungerei gli osservatori in viewWillAppear perché viene chiamato più di una volta. Tuttavia, potrebbe non essere un problema poiché probabilmente non si otterranno chiamate ridondanti al gestore a causa della coalescenza delle notifiche.

6

Hai appena sentito un grande limite di ViewControll iOS: succhiano alla testabilità.

  • ViewControllers mescolano logica di gestire la visualizzazione e il modello

Un altro grosso problema con MVC è che scoraggia gli sviluppatori dai test delle unità di scrittura . Poiché i controller di visualizzazione combinano la logica di manipolazione della vista con la logica aziendale, la separazione di tali componenti per il test dell'unità diventa un'attività di tipo erculeo. Un compito che molti ignorano nel favore di ... semplicemente non testare nulla.

Article - source

Forse si dovrebbe pensare di utilizzare MVVM invece. Questo è un ottimo articolo che spiega la differenza tra iOS MVC e MVVM.

La cosa grandiosa dell'utilizzo di MVVM è che è possibile utilizzare DataBinding utilizzando Reactive Cocoa. Here's un tutorial che spiegherà Data Binding con MVVM e programmazione reattiva in iOS.

Problemi correlati