Come configurare il sistema di build per il test dell'unità + simulazione?

6

Abbiamo una base di codice legacy interamente in C ++. Il nostro sistema di build è CMake. La mia prima pugnalata al test unitario è stata la seguente:

  • Definisci un obiettivo ( LibraryA ). Questa libreria contiene il codice da testare.
  • Definisci un target di test unitario per file di test CPP in LibraryA in fase di test e link contro LibraryA.lib .

Fondamentalmente la struttura di origine è così:

LibraryA/
  Source/
    Utils/
      MyClass.cpp
      MyClass.hpp
      AnotherClass.cpp
      AnotherClass.hpp
    Network/
      Socket.cpp
      Socket.hpp
  Tests/
    Utils/
      TestMyClass.cpp
      TestAnotherClass.cpp

Quello che abbiamo qui è una struttura a specchio della directory Source all'interno di Tests . Questa struttura mi permette di usare l'inclusione degli ordini al livello della riga di comando del compilatore per dare la priorità a dove trovare le intestazioni delle classi per scopi di derisione. Ogni file Test*.cpp in Tests risulta in 1 eseguibile. Quindi 1 test eseguibile per classe in fase di test.

Il problema è che sto collegando LibraryA.lib nel mio eseguibile di test. Ciò si traduce in violazione ODR perché se voglio prendere in giro la classe Socket, il LibraryA.lib avrà già compilato simboli in esso. Ora non riesco a deriderlo senza duplicare i simboli e il linker si lamenterà.

L'impostazione generale della struttura di test delle unità è stata una grande sofferenza dal punto di vista del sistema di costruzione quando si tratta di prendere in giro.

C'è una buona soluzione a questo problema? Il mio approccio alla struttura di test è completamente sbagliato?

    
posta void.pointer 18.06.2015 - 01:21
fonte

2 risposte

2

Ci sono due opzioni:

  • non collegare il binario compilato Socket alla libaryA e compilare la libraryA con i mock. Penso che questo sia quello che stai cercando di fare: collegare l'iniezione delle dipendenze del tempo.
  • usa l'iniezione delle dipendenze di runtime. Aggiungi l'interfaccia per la classe Socket e usa una sorta di dipendenza da dipendenza (factory, costruttore o metodo), e nei test, invece di iniettare il vero Socket, inietta il mock. Questo è ancora meglio, dal momento che puoi testare le chiamate alla simulazione.

L'iniezione delle dipendenze del tempo di collegamento (la prima opzione) significa che si inserisce il codice durante il tempo di collegamento.

Se Socket.h dichiara la classe Socker e Socket.cpp lo implementa, quindi aggiunge un'intestazione che definisce la classe di simulazione con lo stesso nome: Socket. Deve essere nello stesso spazio dei nomi del socket originale.

Quindi quando costruisci il test unitario, non compilare e collegare Socket.cpp, devi compilare e collegare la classe di simulazione e usarla nei test di unità.

    
risposta data 18.06.2015 - 09:16
fonte
1

Semplice: librerie di simulazioni (che simulano entrambi i file .cc e .h) e sii preparato che la stessa libreria sarà derisa in modi diversi per diversi test.

    
risposta data 18.06.2015 - 14:44
fonte

Leggi altre domande sui tag