Organizzazione del progetto C ++ per ridurre i tempi di costruzione dei test unitari

2

Voglio organizzare i test per un progetto abbastanza grande da far riflettere il tempo (specialmente per il server CI).

Dire che ho questo codice che vorrei testare:

//foo/greet.cpp
#include <stdio.h>
#include "foo/greet.h"
int greet() { return printf("Hello, World!\n"); }

E ho questo programma principale che è boilerplate che non testerò.

//main.cpp
#include "foo/greet.h"
int main() { return greet(); }

Userò questo codice per generare un programma unittest

//testgreet.cpp
#include <some_test_framework.h>
SOME_TEST_FRAMEWORK("Testing greet")
    SOME_TEST_FRAMEWORK_ASSERT(greet() > 0)
SOME_TEST_FRAMEWORK_END()

Ho pensato al seguente

  • Ignora la build di greet.cpp per la destinazione non più valida e il collegamento con gli oggetti
  • Crea una struttura di progetto separata per i test, ma condividi la cartella di output
  • Pila tutto in un posto, magari con una nuova cartella chiamata test
  • Crea una libreria di greeting e collega i target principali e quelli di unittests a

Come posso organizzare il mio progetto in modo che possa creare greet.cpp solo una volta, ma ridurre la confusione causata dall'avere due obiettivi che condividono molto codice?

Questa domanda è correlata , ma non duplicata (IMHO).

(+ Ho provato a rendere la mia domanda generica, riutilizzabile e a prova di futuro.Se pensi che sia troppo basata sull'opinione pubblica, vota per chiudere e non ripeterò)

    
posta ixe013 20.02.2014 - 23:19
fonte

3 risposte

4

Il tuo obiettivo è semplicemente di evitare di compilare greet.cpp due volte (una volta per l'applicazione e una volta per i test). Corretto?

Come hai detto tu, ci sono molti modi per farlo. È davvero una questione di quale sistema di generazione stai utilizzando, di come è organizzato il codice e di come vuoi per organizzare il tuo codice.

Utilizza una libreria

Questo è il tuo ultimo suggerimento: crea una libreria greeting e collega gli obiettivi principali e quelli non ancora pubblicati.

Questa è la soluzione più pulita:

  • Rende evidente ciò che stai facendo e dovrebbe funzionare bene con qualsiasi sistema di compilazione o IDE là fuori.
  • Avere l'applicazione e la suite di test condividono la stessa libreria, assicurando che si stia testando il codice pronto per la produzione (invece, per esempio, accidentalmente si utilizzano diverse opzioni del compilatore per l'applicazione contro la suite di test e non si incontrano problemi).
  • Mettere il codice verificabile dell'unità in una libreria può aiutare a incoraggiare un buon design (impedendoti di far scivolare le dipendenze dal codice UI o da altri codici non testabili all'interno della tua libreria).

D'altra parte, potrebbe essere più semplice impostare inizialmente, oppure la progettazione del tuo progetto potrebbe rendere difficile dividere in modo pulito le librerie.

Condividi i file oggetto

I tuoi primi tre suggerimenti sono variazioni su questo. Alcuni sistemi di compilazione lo rendono facile. Ad esempio, il seguente Makefile funzionerebbe:

%.o: %.cpp
  $(CXX) -c $<
main_program: greet.o main.o
  $(CXX) -o $@ $+
unit_tests: greet.o testgreet.o
  $(CXX) -o $@ $+

Se stai usando qualcosa come Make, questo dovrebbe essere molto facile da configurare e iniziare. (Semplicemente per organizzare i tuoi file sorgente, potresti voler mettere le fonti di test in una directory separata, come hai detto.)

Altri sistemi di costruzione rendono questo più difficile. Ad esempio, utilizzando i file di progetto gestiti da IDE e configurando i due progetti IDE per condividere una directory di output, in modo che possano vedere l'output dell'altro, dovrebbe funzionare, ma è un po 'hacker e può invitare problemi se le impostazioni di un progetto divergono in tutto dall'altra (dal momento che una costruzione del progetto può pensare che un file oggetto sia adatto per il proprio uso, anche se è stato costruito utilizzando impostazioni incompatibili dall'altro progetto).

    
risposta data 20.02.2014 - 23:58
fonte
1

Una suite di test unitari è solo un progetto che dipende dal codice testato.

Dato un progetto che raggiunge una certa dimensione, non proprio così grande, si pone la necessità di disporre il codice su un numero di moduli separati (a.k.a. librerie). Mi sembra l'approccio più diretto per avere un progetto di test per ciascuno di questi moduli, e così faccio in pratica. In questo modo, le modifiche all'implementazione di una classe richiedono la ricostruzione del modulo interessato e non più; il progetto di test correlato deve essere nuovamente collegato e quindi rieseguito.

È possibile che una suite di test cresca in eccesso e questo fatto probabilmente suggerisce lo stesso problema nel suo modulo corrispondente. Se questo è il caso, è necessaria un'ulteriore suddivisione.

    
risposta data 21.02.2014 - 00:21
fonte
0

Alcuni framework di test ti consentono di organizzare test in categorie, quindi usalo e poi imposta i test principali da eseguire su ogni commit, e tutto da eseguire su una build notturna che costruisce e testa tutto.

Alcuni altri hanno creato progetti di test unitari - creano 2 set, uno con un set minimo di test inclusi.

Boost :: Test ti consente di eseguire test suite per nome.

Quindi tutto dipende dal framework di test che si utilizza, ma la mia risposta è ancora fondamentalmente: esegui alcuni regolarmente, la suite completa meno regolarmente.

    
risposta data 20.02.2014 - 23:30
fonte