Test di unità o test di integrazione

1

Recentemente ho fatto una domanda sulla progettazione e ho ricevuto suggerimenti su come strutturare il mio codice. Sto ancora lavorando al design quindi ho solo uno pseudo codice, ma questo era quello che avevo in mente.

class TableManager()
{
    int init(DBManager manager, String name)
    {
        this.name = name
        this.manager = manager
    }

    int add_thing(Thing thing) 
    {
        try {
            manager.cursor.execute("INSERT INTO %s, (%s)) % (this.name, thing)
            return 1
        } catch {
            return -1; 
        }
    }

Inizialmente ho pensato che avresti annullato questa operazione inizializzando TableManager nel setup più semplice passandogli un DBManager connesso a localhost e "TEST_TABLE" come argomento del nome.

Quindi chiameresti add_thing con vari stati della tabella. Ad esempio, il primo test chiamerebbe add_thing con una tabella inizialmente vuota. L'unittest controllerebbe quindi lo stato di TEST_TABLE per assicurarsi che la cosa aggiunta fosse nella tabella.

Sono considerati test di integrazione o test di unità?

Qualcuno ha menzionato l'utilizzo di un MockDatabase per testare il gestore di tabelle. Non vedo cosa potrebbe fare? È possibile creare un MockDatabase che restituisce true quando viene chiamato execute, ma non vedo come questo testerebbe la funzionalità di add_thing senza avere effettivamente un database per assicurarsi che l'elemento sia stato aggiunto con successo.

    
posta Handcre 06.01.2017 - 15:40
fonte

2 risposte

2

... I'm still working on design so I only have pseudo code ...

Il tuo codice è il documento di progettazione principale in quanto è l'unico che informa il compilatore su come creare la tua app per te. Non senti mai di dover giustificare la scrittura di codice per aiutare a chiarire i progetti di alto livello.

manager.cursor.execute("INSERT INTO %s, (%s)) % (this.name, thing)

Leggete SQL injection e non create mai istruzioni SQL in questo modo!

Is this considered integration testing or unit testing?

Ci si basa su un effetto collaterale del test (modifica di un database). Quindi tali test sono test di integrazione.

You could create a MockDatabase which just returns true when execute is called, but I don't see how that would test the functionality of add_thing without actually having a database to make sure the element was added successfully.

Hai ragione: questo è un aspetto negativo dei test unitari. Sono veloci e facili da creare, ma testano il codice in isolamento. Potrebbe provare che una sorta di stringa viene passata a manager.cursor.execute , potrebbe anche fare un po 'di analisi della stringa per testarla per la validità, ma per testare veramente questo codice è necessario un vero database e un test di integrazione.

    
risposta data 06.01.2017 - 16:12
fonte
0

Un test unitario verifica se un componente funziona come previsto, in isolamento. L'attenzione si concentra sul comportamento del componente.

Un test di integrazione verifica se più componenti collaborano con successo. L'attenzione è sulla loro interazione.

Un buon quadro mentale per i test unitari è il concetto del valore aggiunto test [1] . Un test unitario non controlla il comportamento completo di un componente incluso il comportamento di altri componenti utilizzati da esso, ma verifica solo il valore aggiunto da quel codice. Perché abbiamo bisogno di quel codice? Cosa succederebbe se lo cancellassimo? Questo dovrebbe essere l'oggetto di un conciso test unitario.

[1]: vedi Codice qualità. Principi, pratiche e modelli di test del software di Stephen Vance.

Qui, il codice in quell'unità chiama solo manager.cursor.execute() con determinati valori e trasforma le eccezioni in valori di ritorno. Per testare quel codice come test unitario "a valore aggiunto", inietteremmo un'istanza di simulazione DBManager . Questo finto asserisce che gli vengono dati determinati valori e possiamo specificare cosa dovrebbe restituire. Possiamo quindi testare:

  • Il cursore DBManager viene chiamato con un argomento stringa specifico.
  • Quando execute() ritorna normalmente, add_thing() restituisce 1.
  • Quando execute() genera, add_thing() restituisce -1.

E questo è tutto ciò che un test unitario dovrebbe fare, perché è tutto il codice che stai testando.

Se utilizziamo un database reale che sarebbe un test di integrazione, non stiamo testando solo la classe, ma anche il DBManager e il sistema stesso del database. I test ora sarebbero:

  • Quando aggiungo una cosa, appare nel database nella tabella corretta.
  • add_thing() restituisce 1 in caso di successo.
  • In caso di errore, add_thing() restituisce -1 (ad es. quando viene utilizzato un nome tabella inesistente).

In pratica, la differenza tra test di integrazione e test unitari non viene disegnata in modo chiaro. Invece di essere puri, i test dovrebbero essere utili. Se ha più valore per testare in modo pulito il tuo TableManager da solo, fallo. Se ha più valore per impostare un database di test, farlo invece. Colloquialmente, tutti i test automatici di singole classi sono chiamati "unit test", anche quando i test si basano su servizi esterni come i database. Tieni presente che i test isolati tendono a correre più velocemente e sono più resistenti alle modifiche non correlate in altre parti del sistema.

    
risposta data 06.01.2017 - 16:16
fonte

Leggi altre domande sui tag