2009-09-17 28 views
15

Ich weiß nicht, wie ihr Jungs Code testet jedes Mal, wenn Sie ein wenig Code und für verschiedene Stufen der Tests: Unit-Tests, Test-Integration, ...Testcode in C C++

Zum Beispiel für Einheit Testen Sie eine Funktion, die Sie gerade geschrieben haben, schreiben Sie noch eine ganze Reihe von Hauptfunktionen und Makefile, um es zu testen? Oder ändern Sie die Hauptfunktion Ihres Projekts, um die Funktion zu testen. Oder führen Sie Ihr Projekt nur unter Debugging aus und halten Sie an, wo die Funktion aufgerufen wird, und ändern Sie die Werte ihrer Argumente?

Ich glaube, es muss einige bequeme und gemeinsame Wege geben, die die meisten Menschen benutzen und nur mir nicht bewusst ist.

Antwort

3

xUnit ist eine Familie von Komponententestmodulen. x wird durch einen Buchstaben für die verwendete Sprache ersetzt. Die Familie besteht derzeit aus:

Ich habe in Projekten mit CppUnit mit guten Ergebnissen gearbeitet. Vor kurzem habe ich versucht, dies in eine automatische Build-Umgebung (d. H. Hudson) zu integrieren und stieß dabei auf viele Hindernisse.

Im Idealfall erstellt der Build automatisch die Komponententests und führt sie aus. In diesem Fall wird der Code von der Testumgebung ausgeführt (und hat somit eine eigene Hauptschleife). Eine zusätzliche Komplikation in meinem Fall ist, dass ich mit eingebetteten Systemen arbeite; printf ist nicht immer möglich. Ich erwarte, dass, wenn Sie auf dem PC laufen, Cnnit und CppUnit Ihnen sehr dabei helfen können, gute Komponententests durchzuführen. Bitte schauen Sie sich an, wie Sie die Ergebnisse verwenden können. Ein kontinuierliches Integrationssystem wird Ihre Effizienz erheblich steigern.

Ein weiterer Rahmen, der einen Blick wert ist, ist Maestra. Es stützt sich auf C99 (das Microsoft nie implementiert hat, aber für GCC ist es großartig!)

4

Ich benutze googletest/gtest

+1

GoogleTest ist ein nettes einfach zu bedienendes Paket. Es ist auch gut dokumentiert. Der einzige Grund, warum ich auf cpptest umgestiegen bin, ist, dass die Google-Makros so komplex sind, dass sie das Parsing und Completion meiner IDE zum Scheitern bringen. Es ist nicht googeltest Schuld, aber es ist immer noch ein Problem. – Jay

2

ich in der Regel auf diese Weise:

int foo(int bar) { 
    ... 
} 

#ifdef FOO_UNITTEST 
int main(int argc, char *argv[]) { 
    // tests 
} 
#endif 

Und ich habe eine Make-Datei, die -DFOO_UNITTEST in CFLAGS hat.

Es ist ungeschickt, aber Sie haben immer Ihre Tests direkt neben Ihrem Code.

+0

+1 Gute Demonstration eines grundlegenden Komponententests. –

1

Sie sollten auch ein Testabdeckungs-Tool ausführen, um zu sehen, ob Ihre Tests tatsächlich genug vom Code ausführen, um eine gute Testgruppe zu sein. Siehe SD Test Coverage for C.

0

Normalerweise beginne ich mit etwas so kompliziert wie MinUnit dann erstellen Sie eine Reihe von Makros, die zu dem Projekt passt, das ich arbeite, um den Konventionen dieses Projekts zu entsprechen.

Jede Komponente verfügt über eine ausführbare Datei, die die Komponententests für diese Komponente erstellt und ausführt.

Ich benutze keinen Debugger, da dies einen menschlichen Eingriff erfordert, so dass Sie ihn nicht für die automatische Regression verwenden können. Ich ändere die Hauptprogrammdatei nicht, da diese normalerweise viele Komponenten beinhaltet und ziemlich kompliziert genug ist, ohne viele Makros zu haben, um Bits ein- und auszuschalten. Das Erstellen eines neuen Ziels mit make ist sehr einfach.

9

Der Ansatz der Test Driven Development (TDD) ist zunächst den Test schreiben, sehen, dass es standardmäßig fehlschlägt (dh ein neues Der Test ist erfolgreich, wenn er fehlgeschlagen ist. Schreiben Sie dann die Funktion, um den Test zu bestehen.

Auf diese Weise wird das Testen nicht nur ein nachträglicher Einfall, sondern der Kern Ihrer Entwicklungsmethodik.

Da Sie möglicherweise eine Funktion (Methode) entwickeln, bevor Sie die Objekte implementiert haben, auf denen es funktioniert, bieten die meisten TDD-Frameworks auch eine Möglichkeit zum Erstellen von "Mock" -Objekten, die erwartete Ergebnisse zurückgeben, bevor ihre Klassen tatsächlich implementiert werden .

ich persönlich Google-Test und Google Mock empfehlen:

http://code.google.com/p/googletest/

http://code.google.com/p/googlemock/

1

I UnitTest++ lieben. Es ist wirklich einfach einzurichten und das Schreiben von Tests ist einfacher als mit dem typischen Favoriten, CppUnit. Jeder Test hat sehr wenig Programmieraufwand, also schreiben Sie sie eher!

Für das, was ich testen, tendiere ich dazu, die öffentlichen Schnittstellen von Klassen zu testen, aber wenn ich nur etwas Refactoring mache und Dinge in kleinere Funktionen zersplittere, schreibe ich keine Tests für jede dieser Funktionen - Sie sollten von den Tests abgedeckt werden, mit denen die öffentliche Schnittstelle getestet wird. Solange die öffentliche Schnittstelle nach den Tests funktioniert, ist alles in der Welt gut.

3

Ich habe gelernt, googletest/googlemock zu lieben. Sie sind eine sehr leistungsfähige Kombination und einfach zu bedienen. Es gibt auch eine Menge Dokumentation auf ihren Wiki-Seiten.

googletest: code.google.com/p/googletest/wiki/GoogleTestPrimer

googlemock: code.google.com/p/googlemock/wiki/ForDummies

2

Ich liebe googletest und googlemock. Sehr einfach zu konfigurieren und gut dokumentiert, here gibt es eine gute Einführung in das Framework.

1

Ich verwende boost.test. Ich habe es von cppunit, das war gut, aber zu java wie, das war ein Problem, weil junit Reflexion verwendet, um Ihre Tests zu finden und auszuführen, da dies nicht in C++ verfügbar ist, müssen Sie Makros verwenden, um Ihre Tests zu registrieren, in cppunit Sie Sie müssen Ihre Tests an drei verschiedenen Orten deklarieren, registrieren und definieren. Mit boost.test können Sie Ihren Test in einer Aussage deklarieren, registrieren und definieren. Das ist sehr schön.

Mein allgemeiner Ansatz ist TDD neuen Code und versuchen, Unit-Test sinnvoll für Legacy-Code zu verwenden. Ich esp Test jeden Code, der auf verschiedenen Plattformen unterschiedlich ist, um sicherzustellen, dass sie sich gleich verhalten und sich weiterhin gleich verhalten.

Ich strukturiere meine Projekte so, dass jede Bibliothek oder jedes ausführbare Projekt auch ein Komponententestprojekt hat. Für ausführbare Tests schließe ich die ausführbaren Quelldateien (außer main) in das Testprojekt ein und füge meinen Test in neue Dateien ein. Bei Bibliothekstests verweise ich normalerweise nur auf die Bibliothek, außer wenn ich private Teile von DLLs teste, dann benutze ich den ausführbaren Ansatz.

Mit CMake können Sie jede Duplizierung zwischen Quellprojekt und Testprojekt abstrahieren. Auch CTest lässt sich gut in jedes Unit-Test-Framework integrieren, das Tests in ausführbaren Dateien packt. Auf diese Weise können Sie alle ausführbaren Testdateien in einer Lösung auf einmal ausführen und eine Zusammenfassung der Ergebnisse anzeigen. Es integriert sich auch in ein kontinuierliches Integrationsframework namens CDash.

Ein Hinweis auf TDD, viele Leute behandeln dies als Test-getriebene Entwicklung, aber es kann Test Driven Design sein. Dies ist eine sehr gute Möglichkeit, sich auf agiles Design zu konzentrieren, TDD zu verwenden, um meine Software zu entwickeln, und es zu schreiben, hat mir wirklich die Augen geöffnet.

7

Vergleichen CppTest und CppUnit Ich würde mit CppTest gehen. CppTest hat weniger versteckten Rahmen und IMO leichter zu verstehen und zu implementieren. Ich persönlich möchte den Haupt Einstiegspunkt sehen. Ich habe auch Boost Unit Testing Framework enthalten. Es ist nicht xUnit basiert. Ich bin kein Fan, aber wenn Sie bereits die Boost-Bibliothek verwenden, wäre es schön zu integrieren.


CppTest vs CppUnit

Einfache einen Komponententest und Test der Erstellung Suite. Sowohl CppUnit als auch CppTest erstellen Komponententests von Klassenmethoden, wobei die Klasse selbst von einer vom Tool bereitgestellten Testklasse abgeleitet wird. Die Syntax für CppTest ist etwas einfacher, obwohl mit der Testregistrierung innerhalb der Klasse Konstruktor geschieht. Bei CppUnit, werden die zusätzlichen Makros CPPUNIT_TEST_SUITE und CPPUNIT_TEST_SUITE_ENDS benötigt.

Durchführung der Tests. CppTest einfach ruft die run-Methode auf dem Test Suite, während CppUnit eine separate Testrunner Klasse, deren Lauf verwendet Methode aufgerufen für die Tests ausgeführt werden.

Erweiterung der Testhierarchie. In Fall von CppTest ist es immer möglich, den vorherigen Test Suite zu erweitern, indem Sie eine neue Klasse erstellen, die von der alten erbt. Die neue Klasse definiert einige zusätzliche Funktionen, die zum Komponententest Pool hinzugefügt werden. Sie rufen einfach die run-Methode für das Objekt des neuen Klassentyps auf. CppUnit erfordert dagegen, dass Sie das Makro CPPUNIT_TEST_SUB_SUITE zusammen mit Klassenvererbung verwenden, um denselben Effekt zu erreichen.

Generierte formatierte Ausgabe. Sowohl CppTest als auch CppUnit verfügen über die Fähigkeit , die Ausgabe anzupassen. Allerdings obwohl CppTest hat eine nützliche, vordefinierte HTML-Ausgabe Formatierer, CppUnit nicht. CppUnit unterstützt jedoch ausschließlich XML-Formatierung. Beide unterstützen Text und Compiler-Stil Formate.

Erstellen von Testvorrichtungen. Um Test Fixtures zu verwenden, erfordert CppUnit, dass die Testklasse von CppUnit :: TestFixture abgeleitet werden. Sie müssen Definitionen für die Setup-und Zerlegungsroutinen bereitstellen. Im Fall von CppTest müssen Sie Definitionen nur für die Setup-und Abbau-Routinen bereitstellen. Dies ist definitiv eine bessere Lösung, da es den Client-Code einfach hält. • Vordefiniert Dienstprogramm Makrounterstützung. Beide CppTest und CppUnit haben einen vergleichbaren Satz von Makros für Geltendmachung, Handhabung von Floats, und so weiter.

Header-Dateien. CppTest erfordert, dass Sie eine einzelne Header-Datei, enthalten, während CppUnit-Client-Code mehrere Header wie HelperMacros.h und TextTestRunner.h je nach den Features enthalten muss.

http://www.ibm.com/developerworks/aix/library/au-ctools3_ccptest/index.html?ca=drs-


CPPTEST

#include “cppTest.h” 

class myTestWithFixtures : public Test::Suite { 
    void function1_to_test_some_code(); 
    void function2_to_test_some_code(); 

    public: 
    myTestWithFixtures () { 
     TEST_ADD (function1_to_test_some_code) {...}; 
     TEST_ADD (function2_to_test_some_code) {...}; 
    } 

    protected: 
    virtual void setup() { ... }; 
    virtual void tear_down() { ... }; 
}; 

int main () 
{ 
    myTestWithFixtures tests; 
    Test::TextOutput output(Test::TextOutput::Verbose); 
    return tests.run(output); 
} 

http://www.ibm.com/developerworks/aix/library/au-ctools3_ccptest/index.html?ca=drs-


CppUnit

#include <cppunit/extensions/TestFactoryRegistry.h> 
#include <cppunit/ui/text/TextTestRunner.h> 
#include <cppunit/extensions/HelperMacros.h> 

class mystringTest : public CppUnit::TestFixture { 
public: 
    void setUp() { ... }; 
    void tearDown() { ... }; 

    void function1_to_test_some_code() { ... }; 
    void function2_to_test_some_code() { ... }; 

    CPPUNIT_TEST_SUITE(mystringTest); 
    CPPUNIT_TEST(function1_to_test_some_code); 
    CPPUNIT_TEST(function2_to_test_some_code); 
    CPPUNIT_TEST_SUITE_END(); 
}; 
CPPUNIT_TEST_SUITE_REGISTRATION(mystringTest); 

mit aus Makros

int main() 
{ 
    CppUnit::TestSuite* suite = new CppUnit::TestSuite("mystringTest"); 
    suite->addTest(new CppUnit::TestCaller<mystringTest>("checkLength", 
       &mystringTest::checkLength)); 
    suite->addTest(new CppUnit::TestCaller<mystringTest>("checkValue", 
       &mystringTest::checkLength)); 

    // client code follows next 
    CppUnit::TextTestRunner runner; 
    runner.addTest(suite); 

    runner.run(); 
    return 0; 
} 

http://www.ibm.com/developerworks/aix/library/au-ctools2_cppunit/


Boost-Unit Testing Framework

#include <boost/test/unit_test.hpp> 

using namespace std; 

struct CMyFooTestFixture 
{ 
    CMyFooTestFixture() { ... } //SetUp 
    ~CMyFooTestFixture() { ... } //TearDown 

    void function1_to_test_some_code(CMyFoo& foo) { ... }; 
    void function2_to_test_some_code(CMyFoo& foo) { ... }; 
} 

BOOST_FIXTURE_TEST_SUITE(MyFooTest, CMyFooTestFixture); 

BOOST_AUTO_TEST_CASE(function1_to_test_some_code) 
{ 
    CMyFoo foo; 
    function1_to_test_some_code(foo); 
} 

BOOST_AUTO_TEST_CASE(function1_to_test_some_code2) 
{ 
    CMyFoo foo; 
    function1_to_test_some_code(foo); 
} 

BOOST_AUTO_TEST_SUITE_END(); 

http://www.beroux.com/english/articles/boost_unit_testing/