Unit test dei componenti interni

14

Fino a che punto si testano i componenti interni / privati di una classe / modulo / pacchetto / ecc.? Li testate o testate semplicemente l'interfaccia con il mondo esterno? Un esempio di questi interni è metodi privati.

Ad esempio, immagina un parser di discesa ricorsivo , che ha diverse procedure interne (funzioni / metodi) chiamate da una procedura centrale. L'unica interfaccia con il mondo esterno è la procedura centrale, che accetta una stringa e restituisce le informazioni analizzate. Le altre procedure analizzano diverse parti della stringa e vengono chiamate dalla procedura centrale o da altre procedure.

Ovviamente, dovresti testare l'interfaccia esterna chiamandola con le stringhe di esempio e confrontandola con l'output analizzato a mano. Ma per quanto riguarda le altre procedure? Li testerete individualmente per verificare che analizzino correttamente le loro sottostringhe?

Posso pensare ad alcuni argomenti:

Pro :

  1. Un maggior numero di test è sempre migliore e questo può aiutare ad aumentare la copertura del codice
  2. Alcuni componenti interni potrebbero essere difficili da fornire input specifici (ad esempio casi limite) dando input all'interfaccia esterna
  3. Test più chiaro. Se un componente interno ha un bug (fisso), un test case per quel componente chiarisce che il bug era in quel componente specifico

Contro :

  1. Il refactoring diventa troppo doloroso e richiede molto tempo. Per cambiare qualcosa, è necessario riscrivere i test unitari, anche se gli utenti dell'interfaccia esterna non sono interessati
  2. Alcune lingue e framework di test non lo consentono

Quali sono le tue opinioni?

    
posta imgx64 04.11.2010 - 07:48
fonte

4 risposte

8

Caso: un "modulo" (in senso lato, cioè qualcosa che ha un'interfaccia pubblica e forse anche alcune parti interne private) ha una logica complicata / implicita al suo interno. Testare solo l'interfaccia del modulo sarà una sorta di test di integrazione in relazione alla struttura interna del modulo, quindi nel caso in cui venga rilevato un errore, tale test non localizzerà l'esatta parte / componente interno responsabile dell'errore.

Soluzione: trasforma le complicate parti interne in moduli, unitali test (e ripeti questi passaggi per loro se sono troppo complicati) e importa nel modulo originale. Ora hai solo un set di moduli abbastanza semplice da uniit test (entrambi controllano che il comportamento sia corretto e corregga gli errori) facilmente, e questo è tutto.

Nota:

  • non sarà necessario modificare nulla nei test dei "sottomoduli" del modulo (precedenti) quando si modifica il contratto del modulo, a meno che il "sottomodulo" non offra più servizi sufficienti per soddisfare il nuovo / contratto modificato.

  • non verrà creato nulla pubblico , cioè il contratto del modulo verrà mantenuto e mantenuto l'incapsulamento.

[Aggiornamento]

Per testare una logica interna intelligente nei casi in cui è difficile mettere le parti interne dell'oggetto (intendo i membri non i moduli / pacchetti importati privatamente) nello stato appropriato semplicemente alimentando gli input tramite l'interfaccia pubblica dell'oggetto:

  • basta avere un codice di prova con un amico (in termini di C ++) o un pacchetto (Java) di accesso alle interiora che in realtà impostano lo stato dall'interno e testano il comportamento come preferisci.

    • questo non interromperà di nuovo l'incapsulamento fornendo al contempo un facile accesso diretto ai componenti interni a scopo di test - basta eseguire i test come una "scatola nera" e compilarli nelle versioni di rilascio.
risposta data 04.11.2010 - 13:40
fonte
2

L'approccio al codice basato su FSM è leggermente diverso da quello usato tradizionalmente. È molto simile a ciò che è descritto qui per i test dell'hardware (che in genere è anche un FSM).

In breve, si crea una sequenza di input di test (o un insieme di sequenze di input di test) che non dovrebbe produrre solo un determinato output, ma anche quando si produce un particolare output "cattivo" consente di identificare il componente guasto in base alla natura del fallimento . L'approccio è abbastanza scalabile, più tempo dedichi al design del test migliore sarà il test.

Questo tipo di test è più vicino a quelli che vengono chiamati "test funzionali" ma elimina la necessità di cambiare test ogni volta che tocchi leggermente un'implementazione.

    
risposta data 04.11.2010 - 09:39
fonte
2

Bene - dipende :-). Se stai seguendo un approccio BDD (Behavior Driven Development) o ATDD (Acceptance Test Driven Development), testare l'interfaccia pubblica va bene (a patto di testarlo in modo esaustivo con diversi input. davvero importante.

Tuttavia, si dice che si desidera che parte di quell'algoritmo venga eseguito entro un certo periodo di tempo o lungo una certa curva bigO (ad esempio nlogn), quindi si testare le singole parti. Alcuni lo chiamerebbero più di un tradizionale approccio TDD / Unit Test.

Come con tutto, YMMV

    
risposta data 04.11.2010 - 10:36
fonte
1

Suddividilo in più parti con un significato funzionale, ad esempio ParseQuotedString() , ParseExpression() , ParseStatement() , ParseFile() e renderle tutte pubbliche. Quanto è probabile che la tua sintassi cambi così tanto da renderli irrilevanti?

    
risposta data 04.11.2010 - 09:04
fonte

Leggi altre domande sui tag