È una cattiva pratica fornire gli argomenti della riga di comando per i test unitari

3

Sono su C ++ e utilizzo gtest come framework principale. Diciamo che ho una funzione di rilevamento dei bordi che voglio testare che prende un'immagine come input e restituisce l'immagine rilevata dal bordo. Ho 3 immagini pronte per essere controllate.

È meglio scriverlo in un modo che è autonomo come

void EdgeCheck(const std::string& input, const std::string& ans) {
    cv::Mat in_img = cv::imread(input);
    cv::Mat ans_img = cv::imread(ans);
    // Do some checks here
}

TEST(Edge) {
    EdgeCheck(std::string("path to image 1"),std::string("path to ans image 1"));
    EdgeCheck(std::string("path to image 2"),std::string("path to ans image 2"));
    EdgeCheck(std::string("path to image 3"),std::string("path to ans image 3"));
}

int main(int argc, char** argv) {
    return UnitTest::RunAllTests();
}

quindi il test può essere eseguito con ./unit-test o è meglio scrivere come

TEST(Edge) {
    cv::Mat in_img = cv::imread(argv[1]);
    cv::Mat ans_img = cv::imread(argv[2]);

    // Do some check here
}

int main(int argc, char** argv) {
    return UnitTest::RunAllTests();
}

ma deve essere eseguito da

./unit-test image1 ans_image1
./unit-test image2 ans_image2
./unit-test image3 ans_image3

Da quanto ho capito, il vantaggio del primo approccio in base agli argomenti della riga di comando UnitTest ++ è "un'unità ben scritta- il test è autonomo e parametrizzare un test significa che il test non è più solo un test, ma ora è una funzione piuttosto che un test unitario. "

Tuttavia, il vantaggio del secondo approccio è che è più flessibile nel senso che se voglio aggiungere image4 e image5, non ho bisogno di ricompilare il codice e può essere fatto su uno script bash, ma poi rende il test non autonomo.

Quale approccio è considerato una pratica migliore?

    
posta user3667089 11.07.2017 - 20:52
fonte

5 risposte

2

Questo è tutto su come si desidera gestire i test e integrarli nell'intero ambiente. Presumo che tu abbia i requisiti per

  • aggiungi facilmente nuovi test
  • esegui tutti i tuoi test contemporaneamente, magari come parte di una suite di test
  • assicurati che un test fallito non impedisca l'esecuzione di altri test indipendenti
  • ottieni in seguito un registro su quale dei tuoi test è fallito e quale no
  • esegui un sottoinsieme dei tuoi test o un singolo test per verificare che non abbia più esito dopo aver applicato una correzione
  • rendere facile per chiunque altro eseguire i test senza conoscenze particolari

Considerando entrambe le tue due soluzioni, penso che renderle parametrizzate dalla riga di comando ti darà più flessibilità per passare da eseguirle singolarmente rispetto a "tutto in una volta", e renderà più semplice accertarsi che un test non funzionante non influenzare altri test. Forse sarà anche più facile integrarli in una suite di test più grande, se hai questa esigenza. Tuttavia, questa flessibilità non è gratis. Poiché è necessario conoscere i parametri, il programma della riga di comando, se chiamato in modo errato, dovrebbe fornire un messaggio descrittivo sul tipo di parametri che si aspetta e lo script dell'esecuzione del test dovrebbe essere parte integrante dei test.

Quindi, finché tratti il programma della riga di comando insieme allo script come un componente autonomo, e finché fornisci qualche documento integrale, non c'è nulla di sbagliato nell'approccio parametrizzato. Se questo non è abbastanza "autonomo" per te per qualche motivo estenuante, integra le cose in un programma, ma convivi con il fatto che gli altri requisiti che ho menzionato potrebbero richiedere più sforzo per risolverlo.

    
risposta data 12.07.2017 - 09:00
fonte
1

I test automatici possono essere parametrizzati senza dipendere dai parametri passati. Spesso un approccio ibrido è più utile.

Ad esempio, se eseguito senza argomenti da riga di comando, il test potrebbe eseguire la scansione di una directory configurata per scorrere tutte le immagini in quella directory.

In questo caso potrebbe essere utile poter sovrascrivere la directory in questo caso e fornire un parametro da riga di comando o specificare una variabile ambientale sono metodi comuni per farlo. Oppure gli utenti possono semplicemente inserire immagini aggiuntive nella directory predefinita per estendere i test.

A well-written unit-test is self-contained, and parameterizing a test means the test is no longer just a test. It's now a function rather than a unit test

@Dymeng è corretto che il tuo test sia probabilmente un test di integrazione e non un test unitario, ma questo è davvero fuori luogo. I test unitari possono essere parametrizzati e quindi anche i test di integrazione.

Il punto sull'essere autonomi è importante. Dovresti essere in grado di eseguire test sul tuo progetto senza specificare gli argomenti della riga di comando, perché se altri utenti volessero eseguire i tuoi test, richiederebbero conoscenze speciali per conoscere i parametri corretti con cui eseguire il test. Ma questo fatto non dovrebbe impedirti di esporre i modi per eseguire il test su altri set di dati.

    
risposta data 12.07.2017 - 03:08
fonte
1

Mi spiace dirlo, ma questa è l'idea peggiore che ho sentito oggi, per diversi motivi:

  • chiunque esegua test di unità, deve passare il parametro corretto nella posizione corretta, altrimenti i test di unità falliranno
  • gtests utilizzano i propri parametri facoltativi e, per questo motivo, non puoi essere sicuro di dove siano i parametri di test (argv [1] o altro indice)

Il meglio per i test di unità se in realtà mettere i dati in test (in una variabile) e (se possibile) non caricare da un file.

    
risposta data 12.07.2017 - 09:15
fonte
1

Secondo The Art of Unit Testing di Roy Osherove, afferma le seguenti proprietà dei test unitari.

1.2. Properties of a good unit test

A unit test should have the following properties:

  1. It should be automated and repeatable.
  2. It should be easy to implement.
  3. Once it’s written, it should remain for future use.
  4. Anyone should be able to run it.
  5. It should run at the push of a button.
  6. It should run quickly.

Con gli argomenti della riga di comando, i test non sono più ripetibili o automatizzati. Posso andare sul tuo computer, premere "Esegui test" e farli funzionare? La risposta è semplicemente no.

Suggerirei di trovare un altro modo per testare l'utilizzo di tali immagini. Forse farne parte del tuo progetto e codificare il percorso relativo?

    
risposta data 13.07.2017 - 22:42
fonte
-2

Penso che per i test unitari non dovresti avere alcuna immagine. Quello che la citazione che hai notato sta cercando di dire è che se stai inserendo un riferimento esterno per il test delle unità, non sei più realmente un test unitario.

Non sono esattamente sicuro di cosa intendi per rilevamento dei fronti, ma immagino ci sia del lavoro all'interno del tuo codice che analizza le proprietà dell'immagine (altrimenti perché hai un'immagine?) poi usa i risultati di tale analisi per eseguire una logica contro.

A un test unitario deve essere fornita una serie di risultati simulati dall'analisi dell'immagine per verificare come viene eseguita la logica contro di esso.

Un test di integrazione, d'altro canto, accetterebbe le immagini come un tipo più ampio di test. In tal caso, è molto meglio passare i dati dell'immagine come parametri (altrimenti si tratta solo di dipendenze hardcoding nei test di integrazione, il che non va bene).

Quindi, penso che non sia tanto una questione di come passare i valori per i percorsi dell'immagine, ma piuttosto capire che c'è una differenza fondamentale tra test unitari e test di integrazione, e quello che stai guardando è il test di integrazione ( ecco perché la citazione non corrisponde per te: si tratta di test unitari).

    
risposta data 11.07.2017 - 21:24
fonte