2010-08-24 10 views
36

Ich verwende Gcov, um Abdeckung in meinem C++ Code zu messen. Ich möchte eine 100% ige Abdeckung erreichen, bin aber dadurch behindert, dass es einige Codezeilen gibt, die theoretisch nicht erreichbar sind (Methoden, die implementiert werden müssen, aber nie aufgerufen werden, Standardzweige von switch Statements, etc.). Jeder dieser Zweige enthält eine assert(false);-Anweisung, aber gcov markiert sie immer noch als nicht getroffen.Wie kann ich gcov anweisen, unhitable Zeilen von C++ Code zu ignorieren?

Ich würde gerne in der Lage sein, gcov zu sagen, diese Zweige zu ignorieren. Gibt es eine Möglichkeit, gcov diese Informationen zu geben - indem Sie den Quellcode oder irgendeinen anderen Mechanismus kommentieren?

+0

Was macht Sie so sicher, dass die Leitungen unhittable sind? Wenn Sie nicht in der Lage sind, sie zu treffen, dann versuchen Sie, dies mit Code-Coverage herauszufinden. – doron

+2

@ deus-ex-machina399: Nein, ich habe es nicht geschafft, sie zu treffen. Es liegt am Verständnis und der Analyse des Codes. Natürlich kann ich mich irren, aber ich verwende keine Code-Coverage-Analyse, um zu versuchen, mein Verständnis des Quellcodes zu verifizieren. Ich verwende Code Coverage-Analyse, um die Qualität meiner Testsuite zu überprüfen. – jchl

+1

@doron, ein Beispiel für Code, der nicht erfassbar sein sollte, sind Fehlerpfade in Ihrer Testinfrastruktur. Natürlich kann man auf solche Wege wahrscheinlich verzichten, aber ich habe sie. –

Antwort

35

Bitte verwenden Sie lcov.Es verbirgt gcov Komplexität erzeugt schöne Leistung, ermöglicht eine detaillierte Ausgabe pro Test zeichnet sich durch einfache Dateifilterung und - ta-taa - Linienmarkierungen für bereits überprüft Linien:

Von geninfo (1):

Die folgende Marker werden durch geninfo erkannt:

  • LCOV_EXCL_LINE
    • Linien diesen Marker enthalten, ausgeschlossen werden.
  • LCOV_EXCL_START
    • markiert den Beginn eines ausgeschlossenen Abschnitt. Die aktuelle Zeile ist Teil dieses Abschnitts.
  • LCOV_EXCL_STOP
    • Markiert das Ende eines Abschnitts ausgeschlossen. Die aktuelle Zeile ist nicht Teil dieses Abschnitts.
+0

Interessant, ich hatte nicht von lcov gehört. Danke für die Empfehlung! – jchl

+0

Schließlich ging es darum, dies zu testen ... und nach dem Upgrade auf eine Version von lcov> = 1.8, es funktioniert ein Charme. Vielen Dank! – jchl

+14

Ich bin kein Fan von Antworten der Form "ein anderes Werkzeug verwenden". Ich möchte tatsächlich wissen, wie man gcov dazu bringt, Zeilen zu ignorieren, und nicht die Möglichkeit, zu lcov zu wechseln. Das beantwortet also die Frage nicht. –

0

Ich glaube nicht, dass das möglich ist. Gcov hängt von gcc ab, um zusätzlichen Code zu generieren, um die Coverage-Ausgabe zu erzeugen. GCov selbst analysiert nur die Daten. Das bedeutet, dass Gcov den Code nicht besser analysieren kann als gcc (und ich nehme an, dass Sie -Wall verwenden und den als unerreichbar gemeldeten Code entfernt haben).

Denken Sie daran, dass verschiebbare Funktionen von überall aufgerufen werden können, möglicherweise sogar externe DLLs oder ausführbare Dateien, so dass der Compiler nicht wissen kann, welche verschiebbaren Funktionen nicht aufgerufen werden oder welche Eingaben diese Funktionen haben.

Sie müssen wahrscheinlich einige statische statische Analyse-Tool verwenden, um die gewünschten Informationen zu erhalten.

1

Könnten Sie Komponententests der relevanten Funktionen einführen, die ausschließlich dazu dienen, gcov durch direkten Angriff auf die theoretisch nicht erfassbaren Codepfade zu schließen? Da sie Unit-Tests sind, könnten sie vielleicht die "Unmöglichkeit" der Situationen ignorieren. Sie könnten die Funktionen aufrufen, die nie aufgerufen werden, ungültige Enumerationswerte übergeben, um Standardverzweigungen usw. abzufangen.

Dann führen Sie entweder diese Tests nur für die Version Ihres mit NDEBUG kompilierten Codes aus, oder führen Sie sie in einem Kabelbaum aus, der testet dass die Bestätigung ausgelöst wird - was auch immer Ihr Test-Framework unterstützt.

Ich finde es ein bisschen seltsam für die Spezifikation zu sagen, dass der Code da sein muss, anstatt die Spezifikation mit funktionalen Anforderungen an den Code. Insbesondere bedeutet dies, dass Ihre Tests diese Anforderungen nicht testen, was ein Grund ist, die Anforderungen zu erfüllen. Persönlich möchte ich die Spezifikation ändern, um zu sagen, "wenn sie mit einem ungültigen Aufzählungswert aufgerufen wird, sollte die Funktion eine assert ausfallen. Anrufer dürfen die Funktion mit einem ungültigen Aufzählungswert im Freigabemodus nicht aufrufen". Oder so etwas.

Vermutlich was es derzeit sagt, ist im Sinne von "alle Switch-Anweisungen müssen einen Standardfall haben". Aber das bedeutet, dass Codierungsstandards das beobachtbare Verhalten stören (zumindest unter gcov beobachtbar), indem sie einen toten Code einführen. Codierungsstandards sollten dies nicht tun, daher sollte die funktionale Spezifikation, wenn möglich, die Codierungsstandards berücksichtigen.

Wenn das nicht klappt, könnten Sie vielleicht den nicht entzifferbaren Code in #if !GCOV_BUILD einfügen und einen separaten Build für gcovs Vorteile erstellen. Dieser Build wird einige Anforderungen nicht erfüllen, aber vorausgesetzt, dass Ihre Analyse des Codes korrekt ist, gibt er Ihnen das Vertrauen, dass Sie wollen, dass die Testsuite alles andere testet.

Bearbeiten: Sie sagen, Sie verwenden einen zweifelhaften Code-Generator, aber Sie fragen auch nach einer Lösung durch Kommentieren des Quellcodes. Wenn Sie die Quelle ändern, können Sie in vielen Fällen einfach den toten Code entfernen? Nicht das Ändern der generierten Quelle ist ideal, aber die Anforderungen müssen ...

+0

Es ist nicht so, dass die "Spezifikation" besagt, dass die Funktionen dort sein müssen. Wir haben einen Code-Generator, der Prototypen für die Funktionen generiert, obwohl sie nicht verwendet werden. (Die Reparatur des Code-Generators wäre eine bessere Option, aber leider liegt das nicht in meiner Hand.) Eine andere Situation, in der dies manchmal auftritt, ist, wo Sie eine Schnittstelle implementieren (dh von einer Klasse mit reinen virtuellen Funktionen ableiten), aber nur verwenden Teil dieser Schnittstelle. – jchl

+0

Einen Komponententest aufzurufen, rufen Sie die Funktionen direkt auf, ist keine schlechte Idee, obwohl die Tests auf einem NDEBUG-Build durchgeführt werden müßten (derzeit testet unser Gerät alle Debug-Builds). Das klingt nach mehr Arbeit als es wert ist. Ich könnte die Behauptungen einfach loswerden, obwohl ich sie dort zu Dokumentationszwecken mag. Ich könnte sie durch eine spezielle Ausnahme ersetzen, die nie erwischt wird, außer während des Komponententests ... das ist keine schlechte Idee. – jchl

+0

@jchl: "Sie implementieren eine Schnittstelle (d. H. Abgeleitet von einer Klasse mit reinen virtuellen Funktionen), verwenden aber nur einen Teil dieser Schnittstelle." - irgendwie. Wenn ich jedoch umfassende Tests für die Klasse schreiben würde, würde ich die Klasse immer noch definieren lassen, was sie tut, und die nicht verwendeten Funktionen aus den Tests aufrufen, um sicherzustellen, dass sie es tun. Und wenn ich nicht umfassende Tests schreiben würde, wäre es mir egal, ob ich Code Coverage hätte oder nicht ;-) –