Was ist der beste Weg zu testen privater Methoden mit GoogleTest?
Ich würde gerne testen einige private Methoden, die mit GoogleTest.
class Foo
{
private:
int bar(...)
}
GoogleTest erlaubt, ein paar Möglichkeiten, dies zu tun.
OPTION 1
Mit FRIEND_TEST:
class Foo
{
private:
FRIEND_TEST(Foo, barReturnsZero);
int bar(...);
}
TEST(Foo, barReturnsZero)
{
Foo foo;
EXPECT_EQ(foo.bar(...), 0);
}
Bedeutet dies: "gtest/gtest.h" in der Produktion Quelle-Datei.
OPTION 2
Erklären test fixture als ein Freund der Klasse und definieren von Zugriffsmethoden in der Leuchte:
class Foo
{
friend class FooTest;
private:
int bar(...);
}
class FooTest : public ::testing::Test
{
protected:
int bar(...) { foo.bar(...); }
private:
Foo foo;
}
TEST_F(FooTest, barReturnsZero)
{
EXPECT_EQ(bar(...), 0);
}
OPTION 3
Den Pimpl-idiom.
Details: Google-Test: Advanced guide.
Gibt es andere Möglichkeiten zum testen von privaten Methoden? Was sind einige vor-und Nachteile jeder option?
Generell sollte man sich nicht unit-testen von privaten Methoden direkt. Stattdessen sollte man mehr schreiben tests für das aufrufen von Methoden, um für die verschiedenen Grenzfälle.
Ich habe aktualisiert die Frage und meine Antwort, damit es nicht so "Meinung". Ich denke, es sollte offen bleiben, da gibt es wahrscheinlich andere Möglichkeiten, dieses problem anzugehen, wurden nicht aufgelistet. Darüber hinaus werden die OP geäußert hat, Sie fand die Antwort hilfreich. Die OP vielleicht finden Sie eine andere Lösung ebenfalls als nützlich.
Es ist oft einfacher und klarer zu testen private (oder protected!) Methoden direkt, aber. Kapselung aus dem Blickwinkel von der Klasse Benutzer kann anders sein als aus dem Blickwinkel der Klasse tester. Unit-tests gemeint sind, zu granular. Wenn der code ist Komplex genug, um getrennt in eine eigene Funktion (private oder nicht), es verdient seinen eigenen unit test.
Ich habe aktualisiert die Frage und meine Antwort, damit es nicht so "Meinung". Ich denke, es sollte offen bleiben, da gibt es wahrscheinlich andere Möglichkeiten, dieses problem anzugehen, wurden nicht aufgelistet. Darüber hinaus werden die OP geäußert hat, Sie fand die Antwort hilfreich. Die OP vielleicht finden Sie eine andere Lösung ebenfalls als nützlich.
Es ist oft einfacher und klarer zu testen private (oder protected!) Methoden direkt, aber. Kapselung aus dem Blickwinkel von der Klasse Benutzer kann anders sein als aus dem Blickwinkel der Klasse tester. Unit-tests gemeint sind, zu granular. Wenn der code ist Komplex genug, um getrennt in eine eigene Funktion (private oder nicht), es verdient seinen eigenen unit test.
InformationsquelleAutor Carlos Perez-Lopez | 2017-11-17
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es mindestens zwei weitere Optionen. Ich werde Liste einige andere Optionen, die Sie betrachten sollten, mit der Erklärung eine bestimmte situation.
Option 4:
Betrachten refactoring von Ihrem code, so dass der Teil, den Sie möchten, um zu testen, ist der öffentlichkeit in einer anderen Klasse. In der Regel, wenn Sie versucht zu test eine Klasse ist private Methode, es ist ein Zeichen von schlechtem design. Eine der häufigsten (anti -) paterns, die ich sehe, ist das, was Michael Feathers fordert ein "Eisberg" - Klasse. "Eisberg" - Klassen haben eine öffentliche Methode, und der rest sind privat (das ist, warum es ist verlockend, zum testen von privaten Methoden). Es könnte wie folgt Aussehen:
Zum Beispiel, möchten Sie vielleicht zu prüfen
GetNextToken()
durch Aufruf auf einer Schnur nacheinander und zu sehen, dass es gibt das erwartete Ergebnis. Eine Funktion wie diese hat garantieren einen test: das Verhalten ist nicht trivial, vor allem, wenn Ihr tokenisierung Regeln sind Komplex. Lassen Sie uns so tun, es ist nicht allzu Komplex, und wir wollen einfach nur Seil in Token, getrennt durch Leerzeichen. So schreiben Sie einen test, vielleicht sieht es etwas wie dieses:Gut, das sieht eigentlich ziemlich nett. Wir wollen sicherstellen, dass wir halten dieses Verhalten, wie wir änderungen vornehmen. Aber
GetNextToken()
ist ein private Funktion! So können wir nicht testen, wie diese, weil es nicht selbst kompilieren. Aber was über das ändern derRuleEvaluator
Klasse zu Folgen, das Prinzip der Einzigen Verantwortung (Single Responsibility-Prinzip)? Zum Beispiel scheinen wir einen parser, tokenizer, und evaluator eingeklemmt in einer Klasse. Wäre es nicht besser, einfach trennen Sie diese Aufgaben? Hinzu kommt, dass, wenn Sie erstellen einTokenizer
Klasse, dann ist es öffentliche Methoden wärenHasMoreTokens()
undGetNextTokens()
. DieRuleEvaluator
Klasse könnteTokenizer
Objekt als Mitglied. Nun, wir halten den gleichen test wie oben, außer wir testen dieTokenizer
- Klasse anstelle derRuleEvaluator
Klasse.Hier ist, was es Aussehen könnte, wie in UML:
Beachten Sie, dass dieses neue design erhöht die Modularität, so könnten Sie möglicherweise re-verwenden Sie diese Klassen in andere Teile Ihres Systems, bevor Sie konnte es nicht private Methoden sind nicht wiederverwendbar per definition). Dies ist der wesentliche Vorteil, dass die RuleEvaluator nach unten, zusammen mit einer erhöhten Verständlichkeit/Lokalität.
Den test Aussehen würde, sehr ähnlich, außer es würde tatsächlich kompilieren dieser Zeit, da die
GetNextToken()
Methode ist jetzt öffentlich auf derTokenizer
Klasse:Option 5
Nur testen nicht die privaten Funktionen. Manchmal sind Sie es nicht Wert zu testen, weil Sie getestet werden, durch die öffentliche Schnittstelle. Viele Male, was ich sehe, ist tests, die Aussehen sehr ähnlich, aber testen Sie zwei verschiedene Funktionen/Methoden. Was am Ende passiert, ist, dass, wenn sich die Anforderungen ändern (und das werden Sie immer tun), haben Sie nun 2 gebrochenen tests statt 1. Und wenn du wirklich getestet, alle Ihre privaten Methoden, die Sie möglicherweise haben mehr wie 10 gebrochen-tests statt 1. In kurz -, Prüf-privaten Funktionen (mit
FRIEND_TEST
oder öffentlich zu machen) , sonst kann getestet werden durch eine öffentliche Schnittstelle, die Ursache test Vervielfältigung. Sie wirklich nicht wollen, denn nichts schmerzt mehr, als deine test-suite Bremsen Sie ab. Es soll verringert Entwicklung Zeit und Wartungskosten zu senken! Wenn Sie testen privater Methoden, ansonsten sind geprüft durch eine öffentliche Schnittstelle, die test-suite kann sehr gut das Gegenteil tun und aktiv zu erhöhen, die Wartungskosten und erhöhen die Entwicklungszeit. Wenn Sie eine private Funktion der öffentlichkeit oder, wenn Sie so etwas wieFRIEND_TEST
werden Sie in der Regel am Ende bereust es.Beachten Sie die folgenden möglichen Umsetzung der
Tokenizer
Klasse:Lassen Sie uns sagen, dass
SplitUpByDelimiter()
ist verantwortlich für die Rückkehr einstd::vector<std::string>
so dass jedes element im Vektor ist ein token. Außerdem, lasst uns einfach sagen, dassGetNextToken()
ist einfach ein iterator über dieses Vektors. So die tests Aussehen könnte:Gut, sagen wir nun, dass sich die Anforderungen ändern, und Sie sind jetzt voraussichtlich zu analysieren, die durch ein "," statt ein Leerzeichen. Natürlich, Sie gehen zu erwarten, dass ein test, um zu brechen, aber die Schmerzen erhöht, wenn Sie die test-private Funktionen. IMO, google test sollte nicht zulassen, dass FRIEND_TEST. Es ist fast nie das, was Sie tun möchten. Michael Feathers bezieht sich auf Dinge wie
FRIEND_TEST
als "Tastend-tool", da es versucht, jemand anderen zu berühren private Teile.Ich empfehle die Vermeidung von option 1 und 2, wenn Sie können, wie es in der Regel bewirkt, dass "test-Duplikation", und als Folge, viele mehr Prüfungen als nötig unterbrochen wird, wenn sich die Anforderungen ändern. Verwenden Sie als letzten Ausweg. Option 1 und 2 sind die Schnellste Möglichkeiten zu "testen privater Methoden" für hier und jetzt (wie in der Schnellste zu implementieren), aber Sie werden wirklich verletzt Produktivität auf lange Sicht.
PIMPL Sinn machen kann, aber es immer noch erlaubt für einige ziemlich schlechtes design. Seien Sie vorsichtig mit ihm.
Ich würde empfehlen, Option 4 (refactoring in kleinere, testbare Komponenten) als den richtigen Ort, um zu starten, aber manchmal ist das, was Sie wirklich wollen ist Option 5 (Prüfung des privaten-Funktionen über die öffentliche Schnittstelle).
P. S. Hier ist die relevante Vorlesung über Eisberg-Klassen: https://www.youtube.com/watch?v=4cVZvoFGJTU
P. S. S. Wie für alles in software, die Antwort ist es hängt. Es gibt keine eine Größe passt alle. Die option, die Ihr problem löst, hängt von Ihrer bestimmten Umstände.
HasMoreTokens
zurückfalse
am Ende des Beispiel-tests (undEXPECT_EQ(result.size(), 4)
fürcanGenerateSpaceDelimitedTokens
)?sicher!!! Gute Anregungen. Vollständigkeit ist wichtig. Schönen Fang!
ich danke Ihnen sehr für Ihre ausführliche Antwort und die Zeit die Sie sich genommen haben es zu schreiben! Dies war mein Erster Stack Overflow Frage-und ich denke, dass Antworten wie diese wirklich helfen, wissen zu teilen. Und ich eigentlich einverstanden mit allem, was Sie gerade gesagt haben. Sie haben mir sehr geholfen. Nochmals vielen Dank!
InformationsquelleAutor Matt Messersmith