write - Unit Testing C-Code




unittest c code (20)

Als C-Neuling fand ich die Folien Test-getriebene Entwicklung in C sehr hilfreich. Im Grunde verwendet es den Standard assert() zusammen mit && um eine Nachricht ohne externe Abhängigkeiten zu liefern. Wenn jemand an ein Full-Stack-Testframework gewöhnt ist, wird dies wahrscheinlich nicht funktionieren :)

Ich habe diesen Sommer an einem eingebetteten System gearbeitet, das in C geschrieben wurde. Es war ein bestehendes Projekt, für das die Firma, für die ich arbeite, übernommen wurde. Ich habe mich daran gewöhnt, Komponententests in Java mit JUnit zu schreiben, aber ich wusste nicht, wie ich Komponententests für vorhandenen Code (der Refactoring benötigt) sowie neuen Code, der dem System hinzugefügt wurde, am besten schreiben konnte.

Gibt es eine Möglichkeit, Komponententests für C-Code zu vereinfachen, so einfach wie das Testen von Java-Code mit JUnit ? Jeder Einblick, der speziell für Embedded-Entwicklung (Cross-Compiling zu Arm-Linux-Plattform) gelten würde, würde sehr geschätzt werden.


Ein Unit-Test-Framework in C ist Check ; Eine Liste von Unit-Test-Frameworks in C finden Sie here und ist im Folgenden wiedergegeben. Abhängig davon, wie viele Standardbibliotheksfunktionen Ihre Runtime besitzt, können Sie möglicherweise eine davon verwenden.

AceUnit

AceUnit (Advanced C und Embedded Unit) bezeichnet sich selbst als ein komfortables C-Unit-Test-Framework. Es versucht, JUnit 4.x nachzuahmen und enthält reflektionsähnliche Fähigkeiten. AceUnit kann in Umgebungen mit Ressourceneinschränkungen verwendet werden, z. B. bei der Entwicklung eingebetteter Software, und vor allem in Umgebungen, in denen Sie keine Standard-Headerdatei aufnehmen können und keine einzelne C-Standardfunktion aus den ANSI / ISO C-Bibliotheken aufrufen kann. Es hat auch einen Windows-Anschluss. Es werden keine Gabeln verwendet, um Signale einzufangen, obwohl die Autoren Interesse daran gezeigt haben, ein solches Merkmal hinzuzufügen. Siehe die AceUnit Homepage .

GNU Autounit

Ähnlich wie Check, einschließlich Forking, um Komponententests in einem separaten Adressraum auszuführen (tatsächlich hat der ursprüngliche Autor von Check die Idee von GNU Autounit ausgeliehen). GNU Autounit verwendet GLib ausgiebig, was bedeutet, dass das Verknüpfen und dergleichen spezielle Optionen benötigen, aber das ist kein großes Problem für Sie, besonders wenn Sie bereits GTK oder GLib verwenden. Siehe die GNU Autounit Homepage .

cUnit

Verwendet auch GLib, forkiert jedoch nicht den Adressraum von Komponententests.

CUnit

Standard C, mit Plänen für eine Win32-GUI-Implementierung. Der Adressraum von Komponententests wird derzeit nicht ausgehandelt oder anderweitig geschützt. In der frühen Entwicklung. Siehe die Startseite von CUnit .

CuTest

Ein einfaches Framework mit nur einer .c- und einer .h-Datei, die Sie in Ihre Quellstruktur einfügen. Siehe die CuTest-Homepage .

CppUnit

Das erste Unit-Testing-Framework für C ++; Sie können es auch verwenden, um C-Code zu testen. Es ist stabil, aktiv entwickelt und hat eine GUI-Schnittstelle. Die Hauptgründe, CppUnit nicht für C zu verwenden, sind erstens, dass es ziemlich groß ist, und zweitens müssen Sie Ihre Tests in C ++ schreiben, was bedeutet, dass Sie einen C ++ - Compiler benötigen. Wenn diese nicht wie Bedenken klingen, ist es eine Überlegung wert, zusammen mit anderen C ++ Unit-Test-Frameworks. Siehe die CppUnit Homepage .

embUnit

embUnit (Embedded Unit) ist ein weiteres Unit-Test-Framework für Embedded-Systeme. Dieser scheint von AceUnit abgelöst zu werden. Startseite der integrierten Einheit .

MinUnit

Ein minimaler Satz von Makros und das war's! Der Punkt ist zu zeigen, wie einfach es ist, den Code in der Unit zu testen. Siehe die MinUnit Homepage .

Komm für Mr. Ando

Eine CUnit-Implementierung, die ziemlich neu ist und anscheinend noch in der frühen Entwicklungsphase ist. Sehen Sie die CUnit für Mr. Ando Homepage .

Diese Liste wurde zuletzt im März 2008 aktualisiert.

Andere:

CMocke

CMocka ist ein Test-Framework für C mit Unterstützung für Mock-Objekte. Es ist einfach zu bedienen und einzurichten. cmocka.org offizielle Homepage.

Kriterium

Criterion ist ein plattformübergreifendes C-Unit-Testframework, das automatische Testregistrierung, parametrisierte Tests und Theorien unterstützt und in mehreren Formaten, einschließlich TAP und JUnit XML, ausgegeben werden kann. Jeder Test wird in einem eigenen Prozess ausgeführt, sodass Signale und Abstürze bei Bedarf gemeldet oder getestet werden können. Weitere Informationen finden Sie auf der Criterion-Startseite .

HWUT

HWUT ist ein allgemeines Einheitentest-Tool mit großer Unterstützung für C. Es kann helfen, Makefiles zu erstellen, massive Testfälle zu generieren, die in minimalen 'Iterationstabellen' codiert sind, entlang Zustandsautomaten laufen, C-Stubs und mehr erzeugen. Der allgemeine Ansatz ist ziemlich einzigartig: Die Urteile basieren auf "good stdout / bad stdout". Die Vergleichsfunktion ist jedoch flexibel. Daher kann jede Art von Skript zum Prüfen verwendet werden. Es kann auf jede Sprache angewendet werden, die eine Standardausgabe erzeugen kann. Siehe HWUT Homepage.


Es gibt CUnit

Und Embedded Unit ist Unit-Test-Framework für Embedded C-System. Sein Design wurde von JUnit und CUnit und mehr kopiert und dann etwas für Embedded C System angepasst. Die integrierte Einheit benötigt keine Standard-C-Bibliotheken. Alle Objekte sind dem Const-Bereich zugeordnet.

Und Tessy automatisiert das Unit-Testing von Embedded-Software.


Es gibt ein elegantes Unit-Test-Framework für C mit Unterstützung für Mock-Objekte namens cmocka . Es erfordert nur die Standard-C-Bibliothek, arbeitet auf einer Reihe von Computerplattformen (einschließlich Embedded) und mit verschiedenen Compilern.

Es unterstützt auch verschiedene Nachrichtenausgabeformate wie Subunit, Test Anything Protocol und jUnit XML-Berichte.

cmocka wurde entwickelt, um auch auf eingebetteten Plattformen zu arbeiten und hat auch Windows-Unterstützung.

Ein einfacher Test sieht so aus:

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>

/* A test case that does nothing and succeeds. */
static void null_test_success(void **state) {
    (void) state; /* unused */
}

int main(void) {
    const struct CMUnitTest tests[] = {
        cmocka_unit_test(null_test_success),
    };
    return cmocka_run_group_tests(tests, NULL, NULL);
}

Die API ist vollständig dokumentiert und einige Beispiele sind Teil des Quellcodes.

Um mit cmocka zu beginnen, sollten Sie den Artikel auf LWN.net lesen: Unit testing with mock objects in C

cmocka 1.0 wurde im Februar 2015 veröffentlicht.




Ich bin überrascht, dass niemand Cutter erwähnt (http://cutter.sourceforge.net/) Sie können C und C ++ testen, es integriert sich nahtlos mit Autotools und hat ein wirklich nettes Tutorial zur Verfügung.


Ich bin nicht weit gekommen, um eine Legacy-C-Anwendung zu testen, bevor ich nach einer Möglichkeit suchte, Funktionen nachzuahmen. Ich brauchte Mocks, um die C-Datei, die ich testen möchte, von anderen zu isolieren. Ich habe versucht, cmock und ich denke, ich werde es übernehmen.

Cmock scannt Header-Dateien und generiert Mock-Funktionen basierend auf gefundenen Prototypen. Mocks können Sie eine C-Datei in perfekter Isolation testen. Alles, was Sie tun müssen, ist, Ihre Testdatei mit Mocks anstelle Ihrer realen Objektdateien zu verknüpfen.

Ein weiterer Vorteil von cmock besteht darin, dass er Parameter validiert, die an mockige Funktionen übergeben werden, und Sie können festlegen, welchen Rückgabewert die Mocks liefern sollen. Dies ist sehr nützlich, um verschiedene Ausführungsabläufe in Ihren Funktionen zu testen.

Tests bestehen aus den typischen testA () -, testB () - Funktionen, in denen Sie Erwartungen aufbauen, Funktionen aufrufen, um Behauptungen zu testen und zu überprüfen.

Der letzte Schritt besteht darin, einen Läufer für Ihre Tests mit Einheit zu generieren. Cmock ist an das Einheitstest-Framework gebunden. Unity ist so einfach zu erlernen wie jedes andere Unit-Test-Framework.

Einen Versuch wert und ganz einfach zu verstehen:

http://sourceforge.net/apps/trac/cmock/wiki

Update 1

Ein anderer Rahmen, den ich untersuche, ist Cmservice.

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

Es ist ein reines C-Framework, das Unit-Testing und Mocking unterstützt. Es hat keine Abhängigkeit von Ruby (im Gegensatz zu Cmock) und es ist sehr wenig von externen Bibliotheken abhängig.

Es erfordert etwas mehr manuelle Arbeit, um Mocks einzurichten, da es keine Code-Generierung durchführt. Für ein bestehendes Projekt ist das nicht viel Arbeit, da sich die Prototypen nicht viel ändern werden: Sobald Sie Ihre Mocks haben, müssen Sie sie für eine Weile nicht mehr ändern (das ist mein Fall). Extra-Typisierung bietet vollständige Kontrolle über Mocks. Wenn es etwas gibt, das du nicht magst, änderst du einfach deinen Schein.

Keine Notwendigkeit eines speziellen Testläufers. Sie müssen nur ein Array von Tests erstellen und an eine run_tests-Funktion übergeben. Ein bisschen mehr manuelle Arbeit hier auch, aber ich mag definitiv die Idee eines in sich geschlossenen autonomen Rahmens.

Außerdem enthält es einige raffinierte C-Tricks, die ich nicht kannte.

Alles in allem braucht Ccomustic ein bisschen mehr Verständnis für Mocks, um loszulegen. Beispiele sollen Ihnen helfen, dies zu überwinden. Es sieht so aus, als könnte es die Arbeit mit einfacheren Mechaniken erledigen.


Ich sage fast das gleiche wie Ratkok, aber wenn Sie eine eingebettete Drehung zu den Unit-Tests haben, dann ...

Unity - Sehr empfohlenes Framework für Unit-Testing-C-Code.

Die Beispiele in dem Buch, das in diesem Thread TDD für eingebettetes C erwähnt wird, werden mit Unity (und CppUTest) geschrieben.


Ich verwende CxxTest für eine eingebettete c / c ++ - Umgebung (hauptsächlich C ++).

Ich bevorzuge CxxTest, weil es ein Perl / Python-Skript zum Erstellen des Testlaufers enthält. Nach einer kleinen Steigung, um es einzurichten (kleiner noch, da Sie den Testläufer nicht schreiben müssen), ist es ziemlich einfach zu benutzen (enthält Proben und nützliche Dokumentation). Die meiste Arbeit bestand darin, die "Hardware" einzurichten, auf die der Code zugreift, damit ich den Unit / Modul-Test effektiv durchführen konnte. Danach können neue Unit-Testfälle einfach hinzugefügt werden.

Wie bereits erwähnt, handelt es sich um ein C / C ++ - Unit-Test-Framework. Sie benötigen also einen C ++ - Compiler.

CxxTest Benutzerhandbuch CxxTest Wiki


LibU ( http://koanlogic.com/libu ) hat ein Komponententestmodul, das explizite Testsuite / Fallabhängigkeiten, Testisolierung, parallele Ausführung und einen anpassbaren Berichtsformatierer erlaubt (Standardformate sind xml und txt).

Die Bibliothek ist BSD-lizenziert und enthält viele weitere nützliche Module - Netzwerk, Debugging, häufig verwendete Datenstrukturen, Konfiguration usw. - falls Sie sie in Ihren Projekten benötigen ...


Michael Feathers Buch "Effectively with Legacy Code" stellt eine Vielzahl von Techniken vor, die spezifisch für Komponententests während der C-Entwicklung sind.

Es gibt Techniken zur Abhängigkeitsinjektion, die spezifisch für C sind, die ich nirgendwo anders gesehen habe.


Persönlich mag ich das Google Test-Framework .

Die eigentliche Schwierigkeit beim Testen von C-Code besteht darin, die Abhängigkeiten von externen Modulen zu trennen, sodass Sie Code in Einheiten isolieren können. Dies kann besonders problematisch sein, wenn Sie versuchen, Tests mit altem Code durchzuführen. In diesem Fall benutze ich häufig den Linker, um Stubs-Funktionen in Tests zu verwenden.

Darauf beziehen sich Leute, wenn sie von " Nähten " sprechen. In C ist Ihre einzige Option wirklich, den Pre-Prozessor oder den Linker zu verwenden, um Ihre Abhängigkeiten zu verspotten.

Eine typische Testsuite in einem meiner C-Projekte könnte folgendermaßen aussehen:

#include "myimplementationfile.c"
#include <gtest/gtest.h>

// Mock out external dependency on mylogger.o
void Logger_log(...){}

TEST(FactorialTest, Zero) {
    EXPECT_EQ(1, Factorial(0));
}

Beachten Sie, dass Sie tatsächlich die C-Datei und nicht die Header-Datei einschließen . Dies bietet den Vorteil des Zugriffs auf alle statischen Datenelemente. Hier verspotte ich meinen Logger (der sich in logger.o befinden könnte, und gebe eine leere Implementierung an. Das bedeutet, dass die Testdatei unabhängig vom Rest der Codebasis kompiliert und verlinkt wird und isoliert ausgeführt wird.

Um den Code zu kompilieren, benötigen Sie gute Einrichtungen auf dem Ziel. Ich habe dies mit googletest cross nach Linux auf einer PowerPC-Architektur kompiliert. Dies ist sinnvoll, weil Sie dort eine vollständige Shell und ein Betriebssystem haben, um Ihre Ergebnisse zu sammeln. Für weniger umfangreiche Umgebungen (die ich als alles ohne vollständiges Betriebssystem klassifiziere) sollten Sie nur auf dem Host erstellen und ausführen. Sie sollten dies trotzdem tun, damit Sie die Tests automatisch als Teil des Builds ausführen können.

Ich finde, dass das Testen von C ++ - Code im Allgemeinen viel einfacher ist, weil OO-Code im Allgemeinen viel weniger gekoppelt als prozedural ist (natürlich hängt dies stark vom Codierungsstil ab). Auch in C ++ können Sie Tricks wie Dependency Injection und Method Overriding verwenden, um Nähte in Code zu bekommen, der ansonsten gekapselt ist.

Michael Feathers hat ein ausgezeichnetes Buch über das Testen von Legacy-Code . In einem Kapitel behandelt er Techniken zum Umgang mit Nicht-OO-Code, die ich sehr empfehle.

Bearbeiten : Ich habe einen Blog-Post über Unit Procedures Code geschrieben, mit Quellcode auf GitHub .

Edit : Es gibt ein neues Buch, das von den Pragmatic Programmers herauskommt, das sich speziell mit Unit Testing C-Code befasst, was ich sehr empfehle .


Schauen Sie zuerst hier: http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C

Meine Firma hat eine C-Bibliothek, die unsere Kunden benutzen. Wir verwenden CxxTest (eine C ++ Unit Test Library), um den Code zu testen. CppUnit wird auch funktionieren. Wenn Sie in C stecken, würde ich RCUNIT empfehlen (aber CUnit ist auch gut).


Vielleicht möchten Sie auch einen Blick auf libtap , ein C-Test-Framework, das das Test Anything Protocol (TAP) ausgibt und sich somit gut in eine Vielzahl von Tools integrieren lässt, die für diese Technologie entwickelt werden. Es wird hauptsächlich in der dynamischen Welt der Sprache verwendet, aber es ist einfach zu bedienen und wird sehr beliebt.

Ein Beispiel:

#include <tap.h>

int main () {
    plan(5);

    ok(3 == 3);
    is("fnord", "eek", "two different strings not that way?");
    ok(3 <= 8732, "%d <= %d", 3, 8732);
    like("fnord", "f(yes|no)r*[a-f]$");
    cmp_ok(3, ">=", 10);

    done_testing();
}

Wenn Sie mit JUnit vertraut sind, empfehle ich CppUnit. http://cppunit.sourceforge.net/cppunit-wiki

Das setzt voraus, dass Sie einen C ++ - Compiler haben, um die Komponententests durchzuführen. Wenn nicht, dann muss ich Adam Rosenfield zustimmen, dass Check das ist, was Sie wollen.


Wir haben CHEAT (auf GitHub ) für einfache Benutzerfreundlichkeit und Portabilität.

Es hat keine Abhängigkeiten und erfordert keine Installation oder Konfiguration. Es wird nur eine Headerdatei und ein Testfall benötigt.

#include <cheat.h>

CHEAT_TEST(mathematics_still_work,
    cheat_assert(2 + 2 == 4);
    cheat_assert_not(2 + 2 == 5);
)

Tests werden in eine ausführbare Datei kompiliert, die sich um die Ausführung der Tests und die Berichterstellung ihrer Ergebnisse kümmert.

$ gcc -I . tests.c
$ ./a.out
..
---
2 successful of 2 run
SUCCESS

Es hat auch schöne Farben.



API Sanity Checker - Test Framework für C / C ++ Bibliotheken:

Ein automatischer Generator von Basiseinheitstests für eine gemeinsame C / C ++ Bibliothek. Es ist in der Lage, (in den meisten, aber leider nicht allen Fällen) Eingabedaten für Parameter zu erzeugen und einfache ("Vernunft" oder "flache") Testfälle für jede Funktion in der API durch die Analyse von Deklarationen im Header zu erstellen Dateien.

Die Qualität der generierten Tests ermöglicht die Überprüfung der Abwesenheit von kritischen Fehlern in einfachen Anwendungsfällen. Das Tool ist in der Lage, generierte Tests zu erstellen und auszuführen und Abstürze (segfaults), Abbrüche, alle Arten von ausgesendeten Signalen, Programm-Rückkehrcode ungleich Null und Programmbehang zu erkennen.

Beispiele:






embedded