Progettazione testabile in Swift

2

Ho cercato tanto a lungo su come progettare classi testabili in Swift, ma ogni sito di informazione descrive solo cose di base come come testare, come affermare, perché è un buon test ...

Il mio attuale design (che non sono così sicuro è il migliore) include una classe singleton ApiClient che viene inizializzata su AppDelegate . Qualcosa del genere:

// Inside AppDelegate#application:didFinishLaunchingWithOptions
ApiClientFactory.make();

// Inside ApiClientFactory
static func make() {
    ApiClient.initialize(
        userProvider: UserProvider(UserLocalRepo(), UserRemoteRepo()),
        booksProvider: BooksProvider(BookLocalRepo(), BookRemoteRepo()),
        ...
    )
}

L'idea era di iniettare nelle classi *Provider s, falsi repository durante il test. Ma a causa del modo in cui VCs è istanziata, non sono sicuro che questo sia un buon progetto, e non sono sicuro di dove iniettare quei finti repo, poiché sembra che AppDelegate#application:didFinishLaunchingWithOptions sia ancora eseguito su test (il che significa ApiClient verrà inizializzato con le classi effettive, non con quelle di simulazione)

    
posta Christopher Francisco 22.06.2015 - 15:35
fonte

2 risposte

4

Penso che tu stia incontrando un punto critico comune durante i test e uno dei motivi per cui non mi piacciono le implementazioni singleton. L'iniezione di queste istanze di repository è un utile schema che consente di sostituire i duplicati di test o di modificare la configurazione del client API in futuro senza dover modificare l'implementazione. Tuttavia, implementandolo come un singleton perdi molto di questa flessibilità, come sembri aver notato. Non solo dovrai gestire il tuo metodo application:didFinishLaunchingWithOptions: chiamato, ma devi anche fare attenzione a non consentire che lo stato condiviso in questo singleton passi da un test a test successivi.

Un'opzione potrebbe essere quella di consentire la modifica di questi repository dopo l'inizializzazione, in modo da poterli successivamente sostituire con i duplicati di prova. Sfortunatamente ciò consente anche una configurazione mutevole che potresti non voler consentire nella tua app.

La mia preferenza sarebbe quella di non usare affatto un singleton e sostituire questa classe ApiClient con un'istanza della classe iniettata in qualsiasi componente abbia bisogno di usarlo. È quindi possibile creare istanze indipendenti isolate per ciascun test secondo necessità. Nella tua applicazione forse avrai ancora una sola istanza di ApiClient , ma ciò non significa che debba essere accessibile tramite i metodi di classe o applicata come vincolo della sua implementazione.

    
risposta data 29.06.2015 - 22:18
fonte
2

I single non sono una buona idea nell'API Apple. Objective-C non supporta i singleton, ma crea un'istanza che blocca la formazione di altri, un lavoro approssimativo su IMHO, che non sempre funziona. Non penso che sia meglio in Swift e visto che deve supportare l'API Objc, ne dubito.

Il metodo preferito per garantire una singola istanza è semplicemente posizionare l'oggetto come una proprietà del delegato dell'app. Dal momento che esiste una sola app e ha un solo delegato e il delegato dell'app è sempre attivo, puoi ottenere tutte le comodità di un singleton senza problemi. Il "singleton" è accessibile anche da qualsiasi punto dell'app, poiché il delegato dell'app è sempre accessibile.

Quindi il test dell'unità procederà normalmente.

    
risposta data 16.07.2015 - 21:43
fonte

Leggi altre domande sui tag