Beim Anwenden von Komponententests auf einigen C-Code stoßen wir auf ein Problem, dass einige statische Funktionen nicht in der Testdatei aufgerufen werden können, ohne den Quellcode zu ändern. Gibt es eine einfache oder vernünftige Möglichkeit, dieses Problem zu lösen?
So testen Sie eine statische Funktion
Ich habe einen Prüfstand. In schlimmen Fällen – wie beim Versuch, eine statische Funktion zu testen, verwende ich:
#include "code_under_test.c"
...test framework...
Das heißt, ich füge die gesamte Datei, die die zu testende Funktion enthält, in die Testumgebung ein. Es ist ein letzter Ausweg – aber es funktioniert.
-
Ich verstehe das nicht. Kann jemand bitte erklären. Danke!
– Bhupesh-Hose
12. November 2014 um 6:35 Uhr
-
@BhupeshPant: Was verstehst du nicht? Wenn eine Funktion ist
static
, ist es außerhalb der Übersetzungseinheit (ungefähr Quelldatei), in der es definiert ist, nicht zugänglich. Die Lösung in der Antwort stellt sicher, dass die zu testende Funktion in dem Code enthalten ist, der sie testet, indem der zu testende Quellcode in die Datei kopiert wird, die ihn über die testet#include "code_under_test.c"
Richtlinie. Der Compiler sieht den zu testenden Code und den Code, der die Tests durchführt, als eine einzige Übersetzungseinheit, sodass der Testcode die statische Funktion aufrufen kann, was sonst unmöglich wäre.– Jonathan Leffler
12. November 2014 um 6:38 Uhr
-
Ich habe es verstanden! Vielen Dank für Ihre schnelle Antwort! warum können wir die Wrapper-Funktionen nicht basierend auf unserem bedingten Kompilierungstyp hinzufügen.
– Bhupesh-Hose
12. November 2014 um 7:21 Uhr
-
Ich habe gerade gesehen, dass sogar @paxdiablo dasselbe sagt.
– Bhupesh-Hose
12. November 2014 um 7:22 Uhr
-
Dies verursacht ein Problem für mich, wenn
code_under_test.c
enthält sowohl statische als auch nicht statische Funktionen und ist mit meiner Testdatei verknüpft. Die nicht statischen Funktionen werden dann zweimal definiert.– Jost
13. April 2017 um 8:15 Uhr
JaredPar
Können Sie weitere Informationen darüber geben, warum Sie die Funktion nicht aufrufen können?
Ist es nicht verfügbar, weil es in einer .c-Datei privat ist? Wenn dies der Fall ist, verwenden Sie am besten eine bedingte Kompilierung, die den Zugriff auf die Funktion ermöglicht, damit andere Kompilierungseinheiten darauf zugreifen können. Zum Beispiel
SomeHeaderSomewhere.h
#if UNIT_TEST
#define unit_static
#else
#define unit_static static
#endif
Fooh
#if UNIT_TEST
void some_method
#endif
Foo.cpp
unit_static void some_method() ...
-
Ich mag diesen Hack. Der einzige Kompromiss besteht darin, ein seltsames Token wie zu hinterlassen
unit_static
im Produktivcode.– shen
29. Januar 2021 um 5:17 Uhr
Bei Komponententests haben wir den Testcode tatsächlich in der Quelldatei selbst und wir kompilieren ihn beim Testen bedingt ein. Dadurch erhalten die Komponententests vollen Zugriff auf alle Funktionen und Variablen auf Dateiebene (statisch oder anderweitig).
Die Unit-Tests selbst sind nicht statisch – dies ermöglicht es uns, die Unit-Tests von einem einzigen Super-Test-Programm aufzurufen, das alle Kompilierungseinheiten Unit-Tests durchführt.
Wenn wir den Code versenden, kompilieren wir bedingt die Komponententests, aber das ist eigentlich nicht notwendig (wenn Sie sicher sein wollen, dass Sie versenden exakt derselbe Code, den Sie getestet haben).
Wir fanden es immer von unschätzbarem Wert, die Komponententests am selben Ort wie den zu testenden Code zu haben, da es offensichtlicher wird, dass Sie die Tests aktualisieren müssen, wenn sich der Code ändert.
-
Ich mache das, wenn der Komponententest klein genug ist, um hineinzupassen. Wenn die Unit-Tests größer werden als die zu testende Quelle, greife ich auf separate Testprogramme zurück, die entweder mit dem Objekt verknüpfen können (wenn nur die externen Abhängigkeiten verwendet werden) oder den Trick in meiner Antwort verwenden, wenn ich mit statischen Funktionen spiele.
– Jonathan Leffler
27. Februar 2009 um 4:02 Uhr
Piep Piep
Nein – Sie können eine statische Funktion nicht direkt testen, ohne die Quelle zumindest ein wenig zu ändern (das ist die Definition von static in C – dass sie nicht von einer Funktion in einer anderen Datei aufgerufen werden kann).
Sie könnten eine separate Funktion innerhalb der Testdatei erstellen, die nur die statische Funktion aufruft?
Zum Beispiel:
//Your fn to test
static int foo(int bar)
{
int retVal;
//do something
return retVal;
}
//Wrapper fn
int test_foo(int bar)
{
return foo(bar);
}
Normalerweise testen wir unsere statischen Funktionen nicht direkt, sondern stellen sicher, dass die von ihnen ausgeführte Logik durch verschiedene Tests der aufrufenden Funktion angemessen getestet wird.
Statische Funktionen sind im Wesentlichen Hilfsfunktionen für die öffentlichen (dh exponierten) Funktionen. IMO sollten Ihre Komponententests also die öffentliche Schnittstelle mit Eingaben aufrufen, die alle Pfade in der statischen Funktion ausführen.
Die Ausgabe (Rückgabewerte / Seiteneffekte) der öffentlichen Funktion sollte verwendet werden, um die Wirkung der Statik zu testen.
Das bedeutet, dass Sie geeignete Stubs haben müssen, um diese Nebenwirkungen „abzufangen“. (z. B. wenn eine Funktion Datei-IO aufruft, müssen Sie Stubs bereitstellen, um diese Datei-IO-Bibliotheksfunktionen zu überschreiben). Der beste Weg, dies zu tun, indem Sie jede Testsuite zu einem separaten Projekt / einer separaten ausführbaren Datei machen und die Verknüpfung mit externen Bibliotheksfunktionen vermeiden. Sie können sogar C-Funktionen simulieren, aber es lohnt sich nicht.
Wie auch immer, das ist der Ansatz, den ich bisher verwendet habe und der für mich funktioniert. Viel Glück
-
Der springende Punkt beim Bottom-Up-Testen ist jedoch, dass Sie es sind nicht müssen “die öffentliche Schnittstelle aufrufen, die alle Pfade in der statischen Funktion ausübt”. Ansonsten ist es so, als würden Sie beim Testen eines Autos auch prüfen, ob jede einzelne Mutter und Schraube ihren Spezifikationen entspricht. Es ist besser, die Muttern- und Schraubenproduktion separat zu testen, und wenn das in Ordnung ist, überprüfen Sie einfach, ob das Auto richtig fährt. Ich bin mir nicht sicher, ob ich das so gut erklärt habe …
– Razzia
29. Dezember 2020 um 12:57 Uhr
-
@Razzie, ich verstehe deinen Punkt. Ich schätze, da zieht man die Linie der Abstraktion. Für mich behandle ich beim Unit-Test die Überprüfung der Mutter als Unit-Test und das ganze Auto als Integrationstest. Statische Funktionen wären in diesem Zusammenhang die Materialzusammensetzung der Mutter. Das Testen statischer Funktionen würde invasive Sonden erfordern, die den Quellcode verschmutzen (wie das Bohren von Löchern in die Mutter).
– Dushara
29. Dezember 2020 um 20:58 Uhr
-
Interessante Idee, aber ich sehe keine Notwendigkeit, statische Funktionen als “nicht Software, sondern Material” zu behandeln. Statische Funktionen (und Makros) in C sind die einfachsten ‘Einheiten’ – ganz unten beim ‘Bottom-Up-Testing’. Am einfachsten sind sie am einfachsten für einen “Einheitentest”: Übergeben Sie eine Reihe von Eingabeargumenten und überprüfen Sie die Ausgabeargumente und alle Rückgabewerte. Idealerweise würden diese Tests in der Nähe des Codes selbst gehalten, wie eine „Selbsttest“-Taste auf einem Gerät, das Sie in einem Geschäft kaufen.
– Razzia
30. Dezember 2020 um 13:26 Uhr
Gast
#define static
Das ist eine sehr schlechte Idee. Wenn Sie eine Variable lokal für eine Funktion deklariert haben, ändert sie das Verhalten der Funktion. Beispiel:
static int func(int data)
{
static int count = 0;
count += data;
return count;
}
Sie könnten die Funktion aus dem Komponententest aufrufen, da func() exportiert würde, jedoch würde die grundlegende Funktionalität des Codes geändert.
-kurt
-
Der springende Punkt beim Bottom-Up-Testen ist jedoch, dass Sie es sind nicht müssen “die öffentliche Schnittstelle aufrufen, die alle Pfade in der statischen Funktion ausübt”. Ansonsten ist es so, als würden Sie beim Testen eines Autos auch prüfen, ob jede einzelne Mutter und Schraube ihren Spezifikationen entspricht. Es ist besser, die Muttern- und Schraubenproduktion separat zu testen, und wenn das in Ordnung ist, überprüfen Sie einfach, ob das Auto richtig fährt. Ich bin mir nicht sicher, ob ich das so gut erklärt habe …
– Razzia
29. Dezember 2020 um 12:57 Uhr
-
@Razzie, ich verstehe deinen Punkt. Ich schätze, da zieht man die Linie der Abstraktion. Für mich behandle ich beim Unit-Test die Überprüfung der Mutter als Unit-Test und das ganze Auto als Integrationstest. Statische Funktionen wären in diesem Zusammenhang die Materialzusammensetzung der Mutter. Das Testen statischer Funktionen würde invasive Sonden erfordern, die den Quellcode verschmutzen (wie das Bohren von Löchern in die Mutter).
– Dushara
29. Dezember 2020 um 20:58 Uhr
-
Interessante Idee, aber ich sehe keine Notwendigkeit, statische Funktionen als “nicht Software, sondern Material” zu behandeln. Statische Funktionen (und Makros) in C sind die einfachsten ‘Einheiten’ – ganz unten beim ‘Bottom-Up-Testing’. Am einfachsten sind sie am einfachsten für einen “Einheitentest”: Übergeben Sie eine Reihe von Eingabeargumenten und überprüfen Sie die Ausgabeargumente und alle Rückgabewerte. Idealerweise würden diese Tests in der Nähe des Codes selbst gehalten, wie eine „Selbsttest“-Taste auf einem Gerät, das Sie in einem Geschäft kaufen.
– Razzia
30. Dezember 2020 um 13:26 Uhr
A. Michailow
Wenn Sie sich in einer Unix-Umgebung befinden, können Sie einen zusätzlichen Header in die Testdatei aufnehmen yourheader_static.h
mit Deklarationen Ihrer statischen Funktionen und übersetzen Sie die obj-Datei code_under_test.o
durch objdump --globalize-symbols=syms_name_file
lokale Symbole zu globalisieren. Sie sind sichtbar, als ob sie nicht statische Funktionen wären.
Mögliches Duplikat von Wie teste ich eine Klasse, die private Methoden, Felder oder innere Klassen hat?
– Raedwald
14. Dezember 2017 um 12:48 Uhr
Definitiv kein Duplikat einer Frage, die für C++ oder eine andere OO-Sprache sein muss, da C keine Klassen, privaten Methoden, Felder oder inneren Klassen hat.
– Jonathan Leffler
14. Februar 2020 um 15:44 Uhr