Frage

Gibt es eine gute Möglichkeit, um Unit-Test-Destruktoren? Wie sagen, ich habe eine Klasse wie dieses (erfundenes) Beispiel:

class X
{
private:
    int *x;

public:
    X()
    {
         x = new int;
    }

    ~X()
    {
         delete x;
    }

    int *getX() {return x;}
    const int *getX() const {return x;}
};

Gibt es eine gute Möglichkeit, um Unit-Test diese sicher x machen gelöscht wird meine HPP-Datei mit #ifdef TESTS ohne unübersichtlich oder Verkapselung zu brechen? Das Hauptproblem, das ich zu sehen bin, ist, dass es schwierig ist, zu sagen, wenn x bekam wirklich gelöscht, vor allem, weil das Objekt dem Gültigkeitsbereich zu dem Zeitpunkt ist der Destruktor aufgerufen wird.

War es hilfreich?

Lösung

Es kann für Dependency Injection etwas zu sagen sein. Anstatt ein Objekt zu schaffen (in diesem Fall ein int, jedoch in einem nicht-contrived Fall eher ein benutzerdefinierter Typ) in dem Konstruktor, wird das Objekt als Parameter an den Konstruktor übergeben. Wenn das Objekt später erstellt wird, dann wird eine Fabrik an den Konstruktor von X übergeben.

Dann, wenn Sie Unit-Tests sind, übergeben Sie in einem Mock-Objekt (oder eine Mock-Fabrik, die Mock-Objekte erstellt) und der destructor zeichnet die Tatsache, dass es aufgerufen wurde. Der Test schlägt fehl, wenn es nicht ist.

Natürlich kann man nicht spotten (oder auf andere Weise ersetzen) einen eingebauten Typen, so dass in diesem besonderen Fall ist es nicht gut, aber wenn Sie definieren das Objekt / Werk mit einer Schnittstelle, dann können Sie.

Überprüfen auf Speicherlecks in Unit-Tests kann häufig auf einer höheren Ebene durchgeführt werden, wie andere gesagt haben. Aber das nur überprüft, dass a destructor genannt wurde, es nicht beweisen, dass die rechts destructor genannt wurde. So wäre es nicht zum Beispiel fängt eine fehlende „virtuelle“ Erklärung über den destructor von der Art des x Mitglieds (auch hier nicht relevant, ob es nur ein int).

Andere Tipps

Ich denke, Ihr Problem ist, dass Ihr aktuelles Beispiel nicht prüfbar ist. Da Sie wissen wollen, ob x gelöscht wurde, müssen Sie wirklich in der Lage sein x mit einem Mock zu ersetzen. Dies ist wahrscheinlich ein wenig OTT für einen int aber ich denke, in Ihrem realen Beispiel Ihnen eine andere Klasse. Um es testbar zu machen, muss der X Konstruktor für das Objekt bitten, den int Schnittstelle implementieren:

template<class T>
class X
{
  T *x;
  public:
  X(T* inx)
    : x(inx)
  {
  }

  // etc
};

Jetzt wird es einfach in dem Wert für x zu verspotten, und das Mock kann für die korrekte Zerstörung behandeln zu überprüfen.

Bitte achten nicht auf die Leute, die sagen, Sie Verkapselung brechen sollte oder greifen auf schreckliche Hacks, um in prüfbaren Code zu führen. Es stimmt zwar, dass Code getestet ist besser als ungetestet Code, prüfbare Code ist die beste von allen und es ergibt immer klarer Code mit weniger Hacks und unteren Kopplungs.

Ich neige dazu, mit einem gehen „Mit allen notwendigen Mitteln“ -Ansatz zur Prüfung. Wenn es einen Test braucht, bin ich bereit, Abstraktionen zu lecken, brechen Kapselung und hacken ... weil getesteten Code ist besser als recht Code. Ich werde oft die Methoden benennen, die diese bis so etwas wie VaildateForTesting oder OverrideForTesting brechen, um klarzustellen, dass die Verletzung der Verkapselung für die Prüfung nur gemeint ist.

Ich weiß nicht, von irgendeiner anderen Art und Weise dies in C ++ zu tun als in einen Singleton den Destruktoraufrufs mit registrieren, dass es zerstört wurde. Ich habe mit einem Verfahren kam für etwas ähnliches wie dies in C # tut eine schwache Referenz verwendet (I nicht gegen Verkapselung oder Abstraktionen mit diesem Ansatz). Ich bin nicht kreativ genug mit einer Analogie zu C ++ zu kommen, aber Sie könnten sein. Wenn es hilft, große, wenn nicht, sorry.

http://houseofbilz.com/archive/2008/11/11/writing-tests-to-catch-memory-leaks-in-.net.aspx

Im Beispiel definieren und Instrument, um Ihre eigenen globalen neu und löschen.

Um zu vermeiden, #ifdefs, habe ich Testklassen Freunde machen. Sie können einstellen / speichern / get Zustand als die Ergebnisse eines Aufrufs zur Überprüfung erforderlich ist.

Es wird nicht an den Mann relevant sein, der die Frage gestellt, aber vielleicht für andere hilfreich sein, der dies liest. Ich war eine ähnliche Frage in einem Vorstellungsgespräch gefragt.

Unter der Annahme, der Speicher begrenzt ist, können Sie versuchen, diese Methode:

  1. Weisen Speicher, bis die Zuweisung mit der Speicher-Nachricht fehlschlägt (vor allen relevanten Test zum destructor ausgeführt wird) und die Größe des verfügbaren Speichers speichern, bevor der Test ausgeführt wird.
  2. Führen Sie den Test (den Konstruktor aufrufen und einige Aktionen ausführen, wie Sie auf der neuen Instanz möchten).
  3. Führen Sie das destructor.
  4. Führen Sie die Zuordnung Teil wieder (wie in Schritt 1) wenn Sie genau den gleichen Speicher zuweisen können, wie Sie vor dem Ausführen des Tests zuzuordnen verwalten, die destructor funktioniert gut.

Diese Methode funktioniert (vernünftigerweise), wenn Sie kleine begrenzten Speicher, sonst scheint es unvernünftig, zumindest meiner Meinung nach.

Einige Compiler überschreiben Speicher mit einem bekannten Muster im Debug-Modus gelöscht, um den Zugriff auf baumelnden Zeiger zu erkennen. Ich weiß, Visual C ++ verwendet 0xdd zu verwenden, aber ich habe es eine Weile nicht verwendet.

In Ihrem Testfall können Sie eine Kopie von x speichern, lassen Sie es außerhalb des Gültigkeitsbereichs gehen und sicherstellen, dass * x == 0xDDDDDDDD:

void testDestructor()
{
    int *my_x;
    {
        X object;
        my_x = object.getX();
    }
    CPPUNIT_ASSERT( *my_x == 0xDDDDDDDD );
}

Nicht ein plattformunabhängig Vorschlag, aber in der Vergangenheit hat ich Anrufe in die CRT-Heap Prüffunktionen während Unit-Tests gemacht, um sicherzustellen, dass es nicht mehr Speicher am Ende eines Tests (oder vielleicht eine ganze Reihe von Tests zugeordnet ist ) als der Start. Vielleicht haben Sie auch in der Lage, etwas ähnliches zu tun mit Ihrer Plattform Instrumentation, auf Griff-Zählungen zu überprüfen, usw.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top