2010-07-14 8 views
6

Typisches Szenario für mich:Wie erzeuge ich den Quellcode, um ein Objekt zu erstellen, das ich debugge?

  1. Der Code Vermächtnis ich arbeite, hat einen Bug, ein Client in der Produktion nur
  2. ich einen Debugger mit anhängen und herauszufinden, wie das Thema auf ihr System zu reproduzieren gegeben ihre Eingabe. Aber ich weiß nicht, warum der Fehler schon passiert ist. Jetzt
  3. Ich möchte einen automatisierten Test auf meinem lokalen System schreiben, um zu versuchen und zu reproduzieren dann fixieren den Bug

Dieser letzte Schritt ist wirklich schwer. Die Eingabe kann sehr komplex sein und viele Daten enthalten. Die Eingabe von Hand zu erstellen (zB: Stellen Sie sich vor, dies 1000 Mal zu tun, um das Objekt zu erstellen) ist sehr mühsam und fehleranfällig. Tatsächlich bemerken Sie vielleicht, dass in dem Beispiel, das ich gerade gegeben habe, ein Tippfehler vorliegt.

Gibt es eine automatisierte Möglichkeit, ein Feld aus einem Haltepunkt in meinem Debugger zu nehmen und den Quellcode zu generieren, die das Objekt schaffen würde, die gleiche Art und Weise bevölkert?

Das einzige, was ich habe kommen mit ist diese Eingabe zu serialisiert (mit Xstream, zum Beispiel). Ich kann das in einer Datei speichern und es in einem automatisierten Test wieder einlesen. Dies hat ein großes Problem: Wenn sich die Klasse auf bestimmte Weise ändert (zB: ein Feld/Getter/Setter-Name wird umbenannt), kann ich das Objekt nicht mehr deserialisieren. Mit anderen Worten, die Tests sind extrem fragil.

+1

Könnten Sie erklären, warum etwas wie XStream nicht passt und warum Sie unbedingt Quellcode generieren müssen? Dies würde sicherlich helfen, bessere Antworten zu erhalten. –

+1

Was ist das Problem mit der langfristigen Zerbrechlichkeit von Testfällen für einen Feldtest, den Sie JETZT lösen möchten? –

+0

@IraBaxter Daran ist kurzfristig nichts auszusetzen. Aber wenn es da draußen eine coole Bibliothek/Technik/Strategie gibt, um damit besser fertig zu werden, als ich derzeit bin, würde ich gerne davon hören. –

Antwort

2

Die Java-Standard-Serialisierung ist bekanntlich nicht sehr nützlich, wenn Objekte ihre Version ändern (Inhalt, Benennung von Feldern). Es ist gut für schnelle Demo-Projekte.

Mehr für Ihre Bedürfnisse geeignet ist der Ansatz, die Ihre eigene (binär) benutzerdefinierte Serialisierung unterstützen objetcs:
Dies ist nicht schwierig, verwenden DataOutputStream schreiben Sie alle Felder eines Objekts. Aber jetzt stellen Sie versiong vor, indem Sie zuerst eine versionId schreiben. Objekte, die nur eine Version haben, schreibe versionId 1. Auf diese Weise können Sie später, wenn Sie eine Änderung an Ihren Objekten vornehmen müssen, Felder entfernen, Felder hinzufügen, die Versionsnummer erhöhen.

solches ICustomSerializable wird dann einfach zuerst die Versionsnummer aus dem Eingangsstrom aus, in einem readObject-() Methode, und je nach Ausführung Id nennen readVersionV1() oder zB readVersionV2().

public Interface ICustomSerializable { 
    void writeObject(DataOutputStream dos); 
    Object readObject(DataInputStream dis); 
} 

public Class Foo { 
    public static final VERSION_V1 = 1; 
    public static final VERSION_V2 = 2; 

    public static final CURRENT_VERSION = VERSION_V2; 
    private int version; 

    private int fooNumber; 
    private double fooDouble; 

    public void writeObject(DataOutputStream dos) { 
    dos.writeInt(this.version); 
     if (version == VERSION_V1) { 
      writeVersionV1(dos); 
     } else (version == VERSION_V2) { 
      writeVersionV2(dos); 
     } else { 
     throw new IllegalFormatException("unkown version: " + this.version); 
     } 
    } 
    public void writeVersionV1(DataOutputStream dos) { 
     writeInt(this.fooNumber); 
     writeDouble(this.fooValue); 
    } 
} 

Weitere Getter und Setter, und ein Konstruktor mit der Version auf CURRENT_VERSION initialisiert wird benötigt.

Diese Art von serialisazion ist sicher zu refactoring, wenn Sie ändern oder fügen Sie auch die entsprechende Lese-und Schreibversion. Für komplexe Objekte, die Klassen aus externen Bibliotheken verwenden und nicht Ihre Kontrolle, kann es mehr Arbeit sein, aber Strings, Listen können leicht serialisiert werden.

+0

Das ist ein interessanter Ansatz. In der Tat dachte ich daran, meinen eigenen Xstream-Serialisierer zu schreiben, um den Quellcode zu schreiben (wenn das sogar eine Option ist). Die Sache, die ich an diesem Vorschlag nicht mag, ist, dass der Build-Breaking wahrscheinlich die Sache sein wird, die mich benachrichtigt, dass ich 'writeVersionV2' implementieren muss. Ich würde es nicht unter dieser Bedingung schreiben wollen. –

1

Ich denke, was Sie tun möchten, speichern ist der „Zustand“, und dann wiederherstellen, dass in Ihrem Test der Fehler, um sicherzustellen, fixiert bleibt.

Kurze Antwort: Es gibt afaik keine solche allgemeine Code-Generierungs-Tool, aber solange mehrere Einschränkungen gehalten werden, schreibt ein solches Tool ist klein Arbeit.

Langer Kommentar: Es gibt Einschränkungen, unter denen diese arbeiten kann. Wenn alles nur Beans mit Getter und Setter für alle Felder ist, die Sie brauchen, dann ist das Generieren von Code dafür nicht so schwierig. Und ja, das wäre sicher umbenennen, wenn Sie den generierten Code zusammen mit dem normalen Code umgestalten. Wenn der Setter fehlt, funktioniert dieser Ansatz nicht. Und das ist nur ein Beispiel dafür, dass dies keine allgemeine Lösung ist.

Refactoring kann beispielsweise auch Felder in andere Klassen verschieben. Wie möchten Sie die Werte aus den anderen Feldern dieser Klasse einführen? Wie können Sie später wissen, ob diejenigen, die Ihren gespeicherten Status geändert haben, immer noch die kritischen Daten enthalten? Oder schlimmer, stellen Sie sich vor, dass das Refactoring dem gleichen Feld eine andere Bedeutung gibt als zuvor.

Die Art des Fehlers selbst ist auch eine Einschränkung. Stellen Sie sich zum Beispiel vor, dass der Fehler passiert ist, weil ein Feld/eine Methode diesen und jenen Namen hatte. Wenn ein Refactoring jetzt den Namen ändert, wird der Fehler unabhängig von Ihrem Status nicht mehr angezeigt.

Das sind nur willkürliche Beispiele, die genau nichts haben mit Ihrem wirklichen Leben Fällen zu tun. Aber dies ist eine Fall-zu-Fall-Entscheidung, keine allgemeine Strategie. Wie auch immer, wenn du deinen Code kennst, der Bug und deine Refactorings sind alle gut genug, um dies zu tun, dann ist ein solches Tool in weniger als einem Tag erledigt, wahrscheinlich viel weniger.

Mit xstream würden Sie teilweise diese erhalten als auch, aber Sie würden die XML-endern haben. Wenn Sie zum Beispiel db4o verwenden, müssten Sie ihm sagen, dass dieses und dieses Feld jetzt diesen und jenen Namen hat.

Verwandte Themen