Qualcuno sta facendo un "vero" TDD con Visual-C ++ e, se sì, come lo fanno? [chiuso]


10

Test Driven Development implica scrivere il test prima del codice e seguire un certo ciclo :

  • Scrivi test
  • Verifica test (esegui)
  • Scrivi il codice di produzione
  • Verifica test (esegui)
  • Pulizia del codice di produzione
  • Verifica test (esegui)

Per quanto mi riguarda, ciò è possibile solo se la soluzione di sviluppo consente di passare rapidamente dal codice di produzione a quello di test e di eseguire il test per una determinata parte del codice di produzione in modo estremamente rapido.

Ora, sebbene esistano molti Unit Testing Frameworks per C ++ (sto usando Bost.Test atm.) Sembra che non esista davvero nessuna soluzione decente (per C ++ nativo ) di Visual Studio (Plugin) che rende il TDD ciclo sopportabile indipendentemente dalla struttura utilizzata.

"Sopportabile" significa che è un clic per eseguire un test per un determinato file cpp senza dover impostare manualmente un progetto di test separato ecc. "Sopportabile" significa anche che un semplice test inizia (collegamento!) E si esegue molto rapidamente .

Quindi, quali strumenti (plugin) e quali tecniche sono disponibili per rendere possibile il ciclo TDD per lo sviluppo C ++ nativo con Visual Studio?

Nota: sto bene con strumenti gratuiti o "commerciali".

Per favore : nessuna raccomandazione quadro. (A meno che il framework non abbia un plug-in Visual Studio dedicato e si desideri consigliare il plug-in.)


Modifica nota : le risposte finora hanno fornito collegamenti su come integrare un framework di unit test in Visual Studio. Le risorse descrivono più o meno come ottenere la compilazione del framework UT e l'esecuzione dei primi test. Questo è non è ciò che questa domanda è circa. Sono dell'opinione che lavorare davvero in modo produttivo, avendo i Test Unit in una manutenzione manuale (!), Vcproj separato dalle tue classi di produzione aggiungerà così tanto sovraccarico che TDD "non è possibile". Per quanto ne so, non si aggiungono "progetti" extra a una cosa Java o C # per abilitare Unit Test e TDD, e per una buona ragione. Questo dovrebbe essere possibile con C ++ dato gli strumenti giusti, ma sembra (questa domanda riguarda) che ci sono pochissimi strumenti per TDD / C ++ / VS.


Cercando su internet, ho trovato uno strumento, VisualAssert , che sembra mirare nella giusta direzione. Tuttavia, non sembra essere molto diffuso (rispetto a CppUnit, Boost.Test ecc.).


Modifica: vorrei aggiungere un commento al contesto per questa domanda. Penso che faccia un buon riassunto del delineare (parte del) problema: (commento di Billy ONeal )

Visual Studio non utilizza "script di compilazione" ragionevolmente modificabili dall'utente. Un progetto produce un binario. Inoltre, Java ha la proprietà che Java non costruisce mai un binario completo: il binario che costruisci è solo un ZIP dei file di classe. Pertanto è possibile compilare separatamente quindi JAR insieme manualmente (usando ad esempio 7z). C ++ e C # collegano entrambi i loro binari, quindi in generale non puoi scrivere uno script del genere. Il più vicino che puoi ottenere è compilare tutto separatamente e quindi fare due collegamenti (uno per la produzione, uno per i test).


2
As far as I am aware, you do not add extra "projects" to a Java or C# thing to enable Unit Tests and TDD,<- Non penso sia corretto. In genere hai più progetti anche in C #; non vuoi spedire il tuo codice di test nel tuo file binario di produzione.
Billy ONeal,

2
Non l'ho mai visto gestito dal framework. La generazione di un binario richiede un progetto. Volete due binari; uno con codice di prova e uno con codice di produzione. Pertanto hai bisogno di due progetti. Non c'è modo di aggirare questo.
Billy ONeal,

1
@BillyONeal, in tutti i miei progetti tranne uno (Java), il progetto contiene la fonte principale e di test: lo script di compilazione seleziona quindi i pezzi da inserire negli artefatti distribuibili.
Robert Mark Bram,

2
@Robert: Visual Studio non utilizza "script di compilazione" ragionevolmente modificabili dall'utente. Un progetto produce un binario. Inoltre, Java ha la proprietà che Java non costruisce mai un binario completo: il binario che costruisci è solo un ZIP dei file di classe. Pertanto è possibile compilare separatamente quindi JAR insieme manualmente (usando ad es 7z.). C ++ e C # collegano entrambi i loro binari, quindi in generale non puoi scrivere uno script del genere. Il più vicino che puoi ottenere è compilare tutto separatamente e quindi fare due collegamenti (uno per la produzione, uno per i test).
Billy ONeal,

4
Sul serio? "Suggerimento: ogni test dovrebbe contenere una funzione principale e generare un eseguibile." Sembra ridicolmente lento per qualsiasi ragionevole quantità di test. Anche se significano solo un dispositivo di prova per eseguibile, il suo consiglio IMO è ancora sciocco. Prova a farlo con migliaia di test (per un progetto di medie dimensioni) o centinaia di migliaia di test (per un progetto di grandi dimensioni) e diventerai sicuramente pazzo.
legalizzare il

Risposte:


4

Ho scritto una serie di blog in 5 parti su TDD con C ++ e Visual Studio: parte 1 , parte 2 , parte 3 , parte 4 , parte 5 .

Non sono sicuro del motivo per cui dici che non fai progetti extra in C # per fare TDD, perché è quello che ho sempre fatto con NUnit e sembra tipico di quello che fanno gli altri anche con NUnit. Il motivo è semplice: tenere sempre il codice di prova separato dal codice di produzione. Per C ++ con Visual Studio, ciò significa progetti separati, proprio come per C # e NUnit. Da quello che so del mondo Java, questo è anche comune lì.

Ovviamente, ognuno ha idee diverse su ciò che è "sopportabile" per fare TDD. Ho praticato il metodo che descrivo nel mio post sul blog per anni severi e lo trovo molto sopportabile. Il C ++ è un linguaggio compilato e la compilazione può essere lenta quando il sistema sotto test è altamente accoppiato. Non c'è modo di sfuggire a questo senza refactoring a un design più liberamente accoppiato.

La mia "azione con un clic" è "Crea soluzione". Se si sta costruendo troppo, è sempre possibile scaricare progetti irrilevanti mentre si sta lavorando e quindi Build Solution costruirà solo il sottoinsieme minimo di progetti necessari per essere aggiornati a seguito delle modifiche.

Certo, la natura del tempo di compilazione di C ++ rende questo richiedere un po 'più tempo in ogni ciclo del processo TDD rispetto a NUnit e C #, ma vale la pena ottenere la fiducia dal mio ben collaudato codice C ++. Altrimenti passerò molto più tempo nel debugger. Vorrei essere prudente nell'usare il tuo uso di gmock in quanto può aggiungere sostanzialmente al tempo di compilazione del test. Finora mi sono quasi sempre allontanato con oggetti "finti" leggeri e raramente ho bisogno della piena funzionalità delle beffe. I framework di derisione per C ++ sono fortemente basati su template e questo può aumentare significativamente i tempi di compilazione, quindi dovrebbero essere riservati dove hai davvero bisogno di un finto e un falso semplicemente non lo farà.

Ho preso in considerazione la creazione di una procedura guidata per il progetto di test di unità Boost.Test per automatizzare parte della natura della piastra della caldaia della creazione del progetto di test per il codice di produzione, ma dopo averlo fatto un paio di volte non è poi così difficile eseguirlo manualmente.

Per quanto riguarda le soluzioni con molti (150?) Progetti, ci sono anche modi per far fronte a questo. Uno ovvio è trovare gruppi di progetti correlati e raggrupparli insieme e iniziare a consumarli / pubblicarli come unità. Se hai davvero bisogno di ricostruire / toccare tutti i 150 progetti per le piccole modifiche che stai apportando durante un ciclo TDD, il tuo codice è così fortemente accoppiato che i test unitari probabilmente non faranno molta differenza.

Guardando il link IDE netbeans, trovo il piacere di avere qualcosa che analizza l'output del test e mostra una piccola riga di test in una finestra con un simbolo verde o rosso accanto a qualcosa che pensavo mi sarebbe mancato venendo da NUnit, ma in realtà non è mancato. Ho trovato più utile che la compilazione fallisse semplicemente e quindi potevo fare doppio clic nella finestra degli errori per posizionare il cursore nella posizione dell'asserzione fallita.


"... non sono sicuro del motivo per cui dici di non fare progetti extra in C # ... Da quello che so del mondo Java, anche questo è comune lì ..." Potrebbe essere stato un errore da parte mia. (Almeno per .NET, perché hai bisogno di un eseguibile per .NET - per Java hai solo bisogno dei file di classe, quindi non vedo bene dove si adatterebbe il progetto extra.)
Martin Ba

Non sono sicuro di come Java lavori con i progetti; Ho un'esperienza limitata lì. Da quel poco che so, capisco che i progetti sono un artefatto dell'IDE e non la lingua. (A rigor di termini, questo vale anche per C #, ma non conosco nessuno che utilizzi il compilatore della riga di comando solo per brevi articoli o dimostrazioni sul blog.) Tuttavia, anche in Java mantieni il codice di test separato da il codice di produzione, che è ciò che i progetti separati stanno facendo per te. Non consiglio mai di compilare in modo condizionale C ++ per separare il codice di produzione e di prova.
legalizzare il

1
"mantieni il codice di test separato dal codice di produzione, che è ciò che i progetti separati stanno facendo per te" - aha! Beh, non proprio, IMHO. Il "progetto" separato è una necessità per C ++ e .NET, poiché entrambi devono creare un eseguibile per eseguire qualsiasi cosa e per creare un (uno) eseguibile è necessario un (uno) progetto. Sto bene mantenendo il codice di test separato (o meno) dal codice di produzione, ma trovo dover aggiungere un "progetto" (ridondante) per generare fastidioso il file eseguibile del test. :-)
Martin Ba

1
Sono necessari due prodotti integrati: codice di produzione (libreria statica, libreria condivisa, eseguibile, ecc.) E un eseguibile di prova. In Visual Studio, ogni prodotto creato corrisponde a un progetto, quindi sono necessari due progetti. Non è davvero più complicato di così. Il progetto di unit test NON è ridondante.
legalizzare il

2

Non sto usando Visual-C ++, ma sto eseguendo TDD con C ++, usando googletest e googlemock, con QtCreator come mio IDE. Anni fa ho avuto una configurazione simile con Visual-C ++ ma utilizzando un diverso framework di unit test.

Ciò che ho trovato utile è di separare il progetto in alcuni sottoprogetti.

  1. Una libreria statica o dinamica che contiene il 99% del codice sorgente del progetto effettivo.
  2. Un progetto che consiste principalmente in un metodo main () per eseguire il normale programma.
  3. Un progetto di test che contiene un main () per eseguire il mio framework di test e molti file contenenti test e oggetti finti.

Con questa configurazione, il mio IDE si occupa dell'aggiunta di file a vari progetti e se le dipendenze vengono determinate correttamente, posso eseguire tutti i miei test unitari con una ricostruzione parziale. Al momento l'ho anche configurato per eseguire tutti i miei test immediatamente dopo la compilazione. Anche Jenkins, l'IC che sto utilizzando, esegue e fornisce risultati dei test e dati di copertura.

Potrebbe essere possibile aggiungere un launcher personalizzato nell'IDE per un file per eseguire i test unitari per il file Foo.cpp se ti è capitato di nominare tutti i test unitari per Foo nel dispositivo di test TestFoo. Come impostarlo esattamente per Visual-C ++ non sono sicuro ma penso che sia possibile.


Informazioni utili, anche se arriverei al punto di chiamarlo il "consiglio comune" :-) ... inoltre non è davvero fattibile per le nostre cose legacy, ma poi aggiungere test alle cose legacy è comunque un dolore ( e mi sarebbe piaciuto rendere meno semplice l'aggiunta del rigging di prova).
Martin Ba,

2

Uso MSTest per testare il codice C ++ nativo.
Ecco il grande post sul blog in questo modo: http://blogs.msdn.com/b/jsocha/archive/2010/11/19/writing-unit-tests-in-visual-studio-for-native-c. aspx

Sì, ci saranno almeno due progetti: uno per l'applicazione stessa, uno per i test.
Invece di creare un terzo progetto con una libreria statica, aggiungo solo il sorgente dell'applicazione al test del progetto, quindi la soluzione è simile alla seguente:

[-] Solution 'Foo'      Foo\Foo.sln
 |-[-] Foo              Foo\Foo\Foo.vcproj
 |  |-[-] include
 |  |  |- foo.h         Foo\Foo\foo.h
 |  |  |- bar.h         Foo\Foo\bar.h
 |  |
 |  |-[-] source
 |     |- foo.cpp       Foo\Foo\foo.cpp
 |
 |-[-] Foo.Tests        Foo\Foo.Tests\Foo.Tests.vcproj
    |                        (Additional include directory: "..\Foo")
    |-[-] include
    |  |- FakeBar.h     Foo\Foo.Tests\FakeBar.h
    |
    |-[-] source
       |-[-] app
       |  |- foo.cpp    Foo\Foo\foo.cpp    -- not in Foo.Tests\
       |
       |-[-] unit-tests
          |- foo_Tests.cpp   Foo\Foo.Tests\foo_Tests.cpp
          |- bar_Tests.cpp   Foo\Foo.Tests\bar_Tests.cpp

Trovo che l'uso del materiale C ++ / CLI per i test unitari offuschi semplicemente le acque durante il test del codice C ++ nativo puro. Tuttavia, ho usato NUnit per testare il codice dell'applicazione C ++ / CLI. Ho scritto i miei test in C # e ha funzionato bene. (La base di codice esistente era C ++ / CLI e non volevo portarla su C #.)
legalizzare il

Inoltre, se i test sono in C ++ / CLI, non è possibile eseguirli su altre piattaforme. La maggior parte dei posti in cui ho usato il C ++ avevano bisogno della capacità di compilazione multipiattaforma. Ovviamente non puoi riutilizzare il progetto VS su altre piattaforme, ma non è un grosso problema avere Makefile o SConscripts per questo.
legalizzare il

@legalize Non possiamo riutilizzare WinAPI (e COM e altre tecnologie specifiche per Windows) anche su piattaforme non Windows.
Abyx,

Sì, ovviamente non è possibile utilizzare tecnologie specifiche di Windows su piattaforme non Windows. La mia osservazione è stata semplicemente che se si dispone di un codice agnostico della piattaforma, non si desidera associare i test unitari a una piattaforma specifica. In un precedente datore di lavoro, abbiamo valutato un gran numero di framework e metodi di unit test. Abbiamo scelto Boost.Test perché era multipiattaforma e se qualcosa dovesse mai finire nella libreria standard C ++ per quanto riguarda i test unitari, molto probabilmente sarebbe Boost.Test.
legalizzare il

2

Forse un po 'tardi, ma se ho letto correttamente la tua domanda, stai cercando tecniche per migliorare il ciclo TDD? Non è stato menzionato qui, ma hai visto gli eventi post-build in VS?

Le nostre soluzioni sono in genere organizzate (con le dipendenze del progetto mostrate) ...

MAIN-APP > LIB1, LIB2, UNIT-TEST-APP
UNIT-TEST-LIB1 > LIB1
UNIT-TEST-LIB2 > LIB2
UNIT-TEST-APP > UNIT-TEST-LIB1, UNIT-TEST-LIB2

L'evento post-build di MAIN-APP eseguirà UNIT-TEST-APP

L'evento post-build di UNIT-TEST-APP si eseguirà da solo (basta inserire '$ (TargetPath)' come comando da eseguire nell'evento post-build).

(Ciò significa che quando si crea MAIN-APP, i test unitari possono essere eseguiti due volte, ma questo non è stato un problema nel nostro caso!)

Come già detto, sì, c'è un po ' di sforzo nell'impostare questa struttura, ma una volta che è lì, aggiungere test è semplice.

Quindi tutto ciò che devi fare è creare l'app principale e i test unitari verranno eseguiti automaticamente!


1

Bene, non so se questo aiuta, ma ci sono alcuni fantastici video su TDD di Brett L. Schuchert. Sfortunatamente, non mostra la combinazione "C ++" e "VS", ma

TDD con C # e VS: http://vimeo.com/album/210446

TDD con C ++ ed Eclipse: http://vimeo.com/13240481

Forse puoi risolverlo da quei due.

EDIT: il video C ++ riguarda l'uso del framwork di test CppUTest con Eclipse, ovviamente. Quando l'ho pubblicato ho pensato che dovesse essere facilmente adottato per l'utilizzo in VS. Quindi ho cercato su Google un po 'e ho trovato questo:

http://schuchert.wikispaces.com/tdd.cpp.NotesOnCppUTest

che fornisce informazioni su come utilizzare CppUTest in Visual Studio.


2
Doc - Ho (solo) guardato il video TDD / Eclipse, ma ho intenzione di sottovalutare questo. Il video mostra esattamente ciò che non mi interessa, ovvero come scrivere il codice Unit Test. Il problema (di questa domanda) non è scrivere Unit Test, è come integrarli correttamente con lo sviluppo della produzione in C ++ e non vedo come questi video possano essere d' aiuto qui.
Martin Ba,

Mentre ho annullato la votazione di questa risposta nel contesto di questa domanda, vorrei aggiungere che i video sono abbastanza belli. Ho trovato interessante Eclipse / TDD / C ++. Semplicemente non aiuta qui :-)
Martin Ba

@Martin: guarda la mia modifica.
Doc Brown,

I tuoi sforzi sono apprezzati e anche se non credo che questo link aggiuntivo sia davvero utile nel contesto di questa domanda, penso che dovrò fare un po 'di editing da solo.
Martin Ba,

@Martin: ok, ho letto di nuovo la tua domanda e la tua definizione di "sopportabile", ma non ti aspetti un po 'troppo? L'impostazione di un progetto di unit test non è una soluzione "one click", ma lo sforzo di scrivere i test unitari effettivi supera quello per ordini di grandezza, qualunque sia il framework che si sta utilizzando.
Doc Brown,

1

Googletest
Come integrarsi con vc ++

Non hai bisogno di un plugin, il test è solo un altro obiettivo. Non ci sono plugin per generare test con c ++, anche se tu potessi testare cose inutili come le assegnazioni


"anche se tu potessi sarebbe testare cose inutili come i compiti" - cosa dovrebbe significare? Pensi davvero che il miglior supporto IDE per i test unitari in C ++ sia inutile ??
Martin Ba,

Voglio dire su un linguaggio come c ++ il sistema non può creare automaticamente test per altro che dichiarazioni ovvie
Martin Beckett,

2
Perchè no? Cosa impedisce a un plugin di generare automaticamente un vcprojfile al volo, inserendo il file di test che ho scritto e il file di produzione di riferimento e provando a eseguirlo? (Sto solo sognando, ma potrebbe funzionare.)
Martin Ba,

2
Non sono sicuro di poterlo seguire. ovviamente devo scrivere io stesso i test . Ma eseguirli potrebbe essere molto più semplice che dover impostare manualmente (e mantenere!) File di test-project separati.
Martin Ba,

2
No, non ho fatto riferimento al codice di prova, ma piuttosto al ponteggio del progetto / compilatore necessario per ottenere il codice di prova più il "codice" di produzione da eseguire.
Martin Ba

1

Non posso commentare gli strumenti C ++ poiché non ho toccato da circa 20 anni (sviluppatore .NET in questi giorni) e immagino che la maggior parte degli strumenti in questi giorni siano per codice gestito ma per quanto riguarda le tecniche ...

Come altri hanno già detto, il codice di test è sempre in un progetto / assembly completamente diverso rispetto al codice di produzione e sì, di solito è necessario mantenere quel progetto da soli, anche se certamente nell'IDE VS questo non è un grosso problema poiché spesso si hanno diversi progetti come parte della tua soluzione comunque.

Il codice di produzione è e deve essere scritto in modo leggermente diverso per TDD. Mentre scrivi prima i test, devi finire per progettare il tuo codice per essere testabile. Questo è tutto un altro argomento in sé, ma può richiedere del tempo e all'inizio sembra molto frustrante, specialmente se i tuoi IDE / strumenti non ti danno un feedback rapido, sborsare per eseguire strumenti da riga di comando per eseguire test è solo dirompente.

Esistono molte tecniche specifiche per rendere testabile il codice, ma la maggior parte di loro si interrompe nel creare piccoli oggetti che non fanno molto, in modo da poterli testare da soli e poter iniettare una versione di prova di alcuni comportamenti in più complessi oggetti. I framework IOC possono aiutare molto qui.

Un libro che potresti trovare utile è; Michael Feathers, che lavora efficacemente con il codice legacy. Questo utilizza più lingue nei suoi esempi e può aiutarti a identificare approcci specifici per adattare in modo sicuro codice / tecniche che non sono stati originariamente progettati per essere testabili.

Piccolo avvertimento: ho bevuto dall'Agile Kool-Aid anni fa: D


Nota: ho già Working Effectively with Legacy Codesulla mia scrivania :-)
Martin Ba

0

Maven non è ampiamente utilizzato in C ++ (tuttavia, viene utilizzato principalmente per Java ma è agnostico in termini di linguaggio) ma è uno strumento molto potente e ti consente di mantenere tutto in un unico progetto (inclusi i test, infatti, che è raccomandato approccio con Maven). Lo suggerisco solo ora, poiché dalle risposte finora sembra che non esista un'alternativa con un plugin VS.

Cercando plugin ho trovato:

http://incubator.apache.org/npanday/

ma non sembra essere ancora molto maturo. Con l'installazione di Maven tutto ciò che dovresti fare per eseguire i test viene eseguito mvn testnella riga di comando.

Se sei interessato, puoi scoprirlo qui e (uno dei) plug-in di supporto C ++ qui (Maven ha un'architettura plug-in, quindi tutto è un plug-in).


0

Raccomandazione quadro: nel nostro ufficio utilizziamo TestDriven.NET che si integra con Visual Studio. Le classi unittest sono scritte in C ++ / CLI, che possono quindi chiamare per esercitare qualunque codice nativo sia necessario testare. Sì, le classi C ++ / CLI vanno nel loro assembly, quindi un progetto di "testing" aggiunto alle soluzioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.