23 Stimmen

Grundlegende Einheitstests und C, wie kann ich anfangen?

Nachdem ich einige Threads hier bei StackOverflow gelesen habe, bin ich zu dem Schluss gekommen, dass ich eine Form der testgetriebenen Entwicklung/Einheitstest übergehen sollte (oder zumindest das Gebiet erkunden sollte).

Und da wir über C-Code unter Linux sprechen, habe ich beschlossen, den siehe ein Versuch (Ich weiß nicht, ob das die richtige Wahl ist, aber wenn es nichts taugt, kann ich später immer noch etwas anderes ausprobieren).

Aber da das Konzept von Unit-Tests und Unit-Test-Frameworks für mich völlig neu ist, Ich habe damit begonnen, einige Unit-Tests an einem wirklich kleinen Testcode durchzuführen (aber ich war sowieso total verloren und hatte das Gefühl, dass mir etwas fehlt).

Bislang habe ich die folgende Datei erstellt:

  • main.c, ein main, das nur eine Funktion namens my_pow aufruft und das Ergebnis ausgibt.
  • my_pow.c, enthält die Funktion my_pow.
  • my_pow.h
  • my_pow_test.c habe ich mir gedacht, dass ich den Unit-Code für die Funktion my_pow hier platzieren sollte.

(Das "normale Programm" besteht also aus main.c, my_pow.c und my_pow.h.)

Dies ist my_pow.c

#include "my_pow.h"
int my_pow(int a, int b)
{
    return (a*b);
}

Dann habe ich herausgefunden, dass ich in my_pow_test.c so etwas wie diese setzen:

#include <check.h>
#include "my_pow.h"

START_TEST (test_my_pow)
{
    /* unit test code */
}
END_TEST

//do I need some sort off main here that calls test_my_pow?

Dies ist im Grunde dasselbe wie in das Kontrollhandbuch Kapitel 3.1, aber noch nicht....

Könnte mich bitte jemand auf den richtigen Weg bringen?

Danke Johan


Update: Kein Grund, warum ich versucht habe, Check zu verwenden, ich dachte nur, ich sollte irgendwo anfangen, vielleicht CUnit ist eine bessere Wahl (ich denke, ich würde versuchen, dass als gut und dann eine fundierte Entscheidung).

Update: Danke @philippe für den indirekten Hinweis, dass die Online-Dokumentation nur die halbe Wahrheit ist, der Beispielcode, der verdeutlicht, wovon die Dokumentation spricht, wurde bereits mit dem check-Paket installiert. Im Fall von Ubuntu /usr/share/doc/check/example/tests/

Aktualisierung: Das Codebeispiel wurde so erstellt, dass Sie sich zunächst seine erste Version ansehen, dann die zweite usw. usw. So konnten Sie verfolgen, wie er einen sehr einfachen Testfall/Code aus dem Nichts heraus zu etwas Nützlichem in traditioneller TTD-Manier erstellt.

Und da mein Code kaputt war und ich wollte, dass der Unit-Test dies beweist, habe ich ein wenig geschummelt und mit der echten pow-Funktion getestet. Etwas wie dies:

START_TEST (test_my_pow1)
{
    int resultat = my_pow(3,3);
    int math     = pow(3,3);
    fail_unless ( resultat == math,
           "Error on 3^3 != %d (%d)",math, resultat);
}

Allerdings werde ich in Zukunft nicht reproduzieren, was bereits in den stdlibs steht :-)


Verwandt:

aus der Suche genommen [c] [unit-testing] .

0 Stimmen

Wissen Sie, dass pow(a,b) != a*b ? ;-)

1 Stimmen

@Aif, ich denke, er weiß es. Aber um die Leistungsfähigkeit von Unit-Tests zu sehen und zu lernen, ist es keine schlechte Idee, mit einer fehlerhaften Funktion zu beginnen.

9voto

philant Punkte 32877

Sie haben einen ersten Testfall erstellt. Jetzt müssen Sie eine Testsuite erstellen (eine Gruppe von Testfällen) und eine Läufer .

Ich würde empfehlen, dass Sie versuchen, die folgende Datei zu kompilieren ihr Beispiel zuerst, um Ihre Umgebung zu überprüfen, obwohl ihre Dokumentation neuen Code über diff (Quellpatch) einführt, was ich nicht sehr praktisch finde.


Sollten Sie sich jemals entscheiden, es mit einem anderen Framework zu versuchen ( Minieinheit kam mir sofort in den Sinn), kann ich Sie auf eine " Lehrgang ".

2 Stimmen

Die obigen Links sind nicht mehr aktuell... verwenden Sie stattdessen diese: Testsuite , Läufer

5voto

Rob Wells Punkte 35303

Ich wäre eher geneigt, mit CUnit das Teil der X-Unit-Reihe von Test-Frameworks ist.

Es ist für große Testsuiten skalierbar und wird schon seit vielen Jahren verwendet, ist also ausgereift.

Gibt es einen Grund, warum Sie sich nicht für CUnit entschieden haben?

HTH

Prost,

Rob

4voto

dbyron Punkte 481

Ich habe mit dejagnu seit Jahren und lieben es.

Ich habe begonnen, es für die Embedded-Entwicklung zu verwenden, weil es sehr gut das Konzept unterstützt, dass der Rechner, auf dem Sie das Testprogramm ausführen, ein anderer sein kann als der Rechner, auf dem Sie das Testprogramm erstellen. Eine Folge davon ist, dass das Testen von Code auf mehreren Plattformen ebenfalls gut unterstützt wird. Ich bin mir nicht sicher, ob das wichtig ist. Die gcc Testsuite verwendet es. Ich verwende sie auch für die Desktop-Entwicklung.

Die Grundidee bei dejagnu ist, dass Sie

  • Kopieren Sie das Testprogramm in das "Ziel" (das für lokale Tests das Verzeichnis ~/tmp sein könnte)
  • Starten Sie das Prüfprogramm
  • Ausgabe auf der Konsole (die als Eingabe für das Testprogramm dient)
  • die Ausgabe des Testprogramms analysieren und mit den Erwartungen abgleichen
  • entscheiden, ob diese Ausgabe "bestanden" oder "nicht bestanden" bedeutet

Wenn Sie das Testprogramm und die Testskripte geschrieben haben, gehen Sie in etwa so vor:

$ runtest
                === foo Summary ===

# of expected passes            42
foo-test built Thu Jan 15 20:09:19 PST 2009
foo-test version 0.0.0.1
runtest completed at Sun Jan 18 08:29:13 2009

Der Weg zum Testen einer Bibliothek namens foo ist folgender:

  • angenommen, die Quell- und Include-Dateien für die Bibliothek befinden sich in ~/src/foo

  • ein Verzeichnis namens ~/src/foo/testsuite erstellen

  • ein Testprogramm mit dem Namen foo-test.c schreiben, das ein main() enthält, das

  • verarbeitet Kommandozeilen-Eingaben

  • - gibt eine Eingabeaufforderung aus und verarbeitet in einer Schleife "Befehle", in der ich einen Befehl zum Testen jeder Funktion in meiner Bibliothek definiere. Dies ist eine Art von Befehls-Shell, aber spezifisch für die Bibliothek. Für etwas wie my_pow würde ich den Befehl so definieren, dass er 2 Argumente benötigt.

  • schreiben Sie eine dejagnu (die eine weitere Schicht über Expect (http://expect.nist.gov/, die selbst eine Schicht über Tcl (http://www.tcl.tk/) ist) Funktion namens my_pow, die:

  • benötigt zwei Argumente

  • Berechnet das erwartete Ergebnis (in Tcl)

  • sendet "my_pow " an die Konsole

  • analysiert die Ausgabe des Befehls my_pow von foo-test

  • bestimmt, ob das tatsächliche Ergebnis mit dem erwarteten Ergebnis übereinstimmt

  • ruft die entsprechende dejagnu-Funktion auf (bestanden oder nicht bestanden)

Klingt hart, ist es aber nicht. Man braucht eine Weile, um zu entscheiden, wie viel Arbeit man in foo-test und wie viel man in Tcl erledigen will. Am Ende verwende ich eine ganze Menge Shell-Funktionen (z. B. Bash), um Dinge wie das Kopieren von Dateien in temporäre Verzeichnisse zu erledigen oder die Protokolldateien einzusehen, die meine Programme erzeugen. Am Ende wird man also gut in all diesen Dingen.

Was die Literatur betrifft, so gibt es ein Buch über Expect, das man unbedingt lesen sollte, wenn man sich mit diesem Thema befassen will: http://oreilly.com/catalog/9781565920903/index.html .
Zwischen dem und einer Online-Referenz für Tcl-Befehle http://www.tcl.tk/man/tcl8.4/TclCmd/contents.htm und FAQ ( http://www.psg.com/~joem/tcl/faq.html ), sind Sie so gut wie am Ziel.

Viel Glück!

-DB

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X