Frage

Ich bin auf der Suche nach einem Werkzeug, das ein Gerät zu testen, wie

nehmen
IPerson p = new Person();
p.Name = "Sklivvz";
Assert.AreEqual("Sklivvz", p.Name);

und erzeugt automatisch die entsprechende Stub-Klasse und die Schnittstelle

interface IPerson         // inferred from IPerson p = new Person();
{
    string Name 
    { 
        get;              // inferred from Assert.AreEqual("Sklivvz", p.Name);
        set;              // inferred from p.Name = "Sklivvz";
    }
}

class Person: IPerson     // inferred from IPerson p = new Person();
{
    private string name;  // inferred from p.Name = "Sklivvz";

    public string Name    // inferred from p.Name = "Sklivvz";
    {
        get
        {
            return name;  // inferred from Assert.AreEqual("Sklivvz", p.Name);
        }
        set
        {
            name = value; // inferred from p.Name = "Sklivvz";
        }
    }

    public Person()       // inferred from IPerson p = new Person();
    {
    }
}

Ich weiß, ReSharper und Visual Studio einige von ihnen tun, aber ich brauche eine komplette Werkzeug - Befehlszeile oder Dingsbums - die automatisch folgert, was getan werden muss. Wenn es kein solches Werkzeug ist, wie würden Sie es schreiben (z ReSharper erstreckt, von Grund auf, mit denen Bibliotheken)?

War es hilfreich?

Lösung

Was Sie scheinen zu brauchen, ist ein Parser für Ihre Sprache (Java), und einen Namen und Typ-Resolver. ( "Symboltabelle Builder").

Nach der Quelltext Parsen, ein Compiler in der Regel einen Namen Resolver hat, dass die Definition von Namen zu erfassen versucht und ihre entsprechenden Typen und eine Typprüfung, die überprüft, dass jeder Ausdruck einen gültigen Typen hat.

Normalerweise wird der Name / Typ Resolver beschwert sich, wenn es keine Definition gibt. Was Sie wollen, es zu tun, ist die „undefiniert“ Sache zu finden, die das Problem verursacht, und einen Typ für sie geschlossen werden.

Für

 IPerson p = new Person();

der Name Resolver weiß, dass "Person" und "IPerson" sind nicht definiert. Wenn es

 Foo  p =  new Bar();

gäbe es keine Ahnung, dass Sie eine Schnittstelle wollten, nur, dass Foo eine Art abstrakt Eltern von Bar ist (beispielsweise eine Klasse oder eine Schnittstelle). So ist die Entscheidung, welcher es muss mit dem Werkzeug bekannt sein ( „wenn Sie ein solches Konstrukt zu finden, übernehmen Foo ist eine Schnittstelle ...“). Sie könnten eine Heuristik verwenden: IFoo und Foo bedeutet IFoo eine Schnittstelle sein sollte, und irgendwo jemand hat Foo als eine Klasse zu realisieren, die eine Schnittstelle zu definieren. Sobald die Werkzeug hat diese Entscheidung getroffen, wäre es seine Symboltabellen aktualisieren müssen, so dass es bewegen auf andere Aussagen:

Für

 p.Name = "Sklivvz";

da p muss eine Schnittstelle sein (von der vorherige Folgerung), dann muss Name ein Feld Mitglied sein, und es scheint, sein Typ String aus der Zuordnung ist.

Damit die Aussage:

 Assert.AreEqual("Sklivvz", p.Name);

Namen und Typ ohne weiteres Problem beheben.

Der Inhalt der IFoo und Foo Einheiten bis zu Ihnen Art ist; Sie mußte nicht und fertig zu verwenden, aber das ist persönlicher Geschmack.

Dies wird nicht so gut funktionieren, wenn Sie mehrere Objekte in derselben Anweisung haben:

 x = p.a + p.b ;

Wir wissen, a und b wahrscheinlich Felder sind, aber Sie können numerischen Typ nicht erraten, was passiert, wenn in der Tat sie numerisch sind, oder wenn sie Strings sind (dies ist legal für Strings in Java, weiß nicht über C #). Für C ++ Sie nicht einmal wissen, was „+“ bedeutet; es könnte ein Bediener auf der Bar-Klasse sein. Also, was Sie tun müssen, ist sammeln Einschränkungen , zum Beispiel „a einige unbestimmte Zahl oder ein String“ usw. und wie das Werkzeug Beweise sammelt, verengt sich die Menge der möglichen Einschränkungen. (Dies funktioniert wie jene Wort Probleme: „Joe sieben Söhne hat Jeff ist größer als Sam Harry kann nicht hinter Sam verstecken ... wer Jeffs Zwilling ist...?“, Wo man die Beweise sammeln müssen und entfernen Sie die Unmöglichkeiten). Sie müssen auch über den Fall kümmern, wo man mit einem Widerspruch enden.

Sie könnten ausschließen P.A + p.b Fall, aber dann können Sie nicht Ihre Unit-Tests ungestraft schreiben. Es gibt Standard-Constraint Solver da draußen, wenn Sie Straflosigkeit wollen. (Was für ein Konzept).

OK, wir haben die Ideen, können nun diese auf praktische Art und Weise getan werden?

Der erste Teil dieser erfordert einen Parser und einen biegbaren Namen und Typ-Resolver. Sie benötigen einen Constraintlöser oder zumindest ein „definierten Wert fließt zu undefinierten Wert“ -Operation (Trivial Constraintlöser).

DMS Software Reengineering Toolkit mit Java Front End könnte dies wahrscheinlich tun. DMS ist ein Werkzeug der Werkzeugbauer, für Leute, die Tools bauen möchten, die Computer langauges in beliebiger Art und Weise verarbeiten. (Denken Sie an „Rechnen mit Programmfragmente statt Zahlen“).

DMS bietet Allzweck-Parsing-Maschinen, und kann einen Baum bauen für was auch immer Frontend es gegeben ist (beispielsweise Java, und es gibt eine C # Frontend). Der Grund, warum ich Java gewählt ist, dass unser Java Frontend hat, dass alle Namen und Typen Auflösung Maschinen, und es wird in Source-Form zur Verfügung gestellt, so dass es gebogen werden kann. Wenn Sie auf die triviale Constraintlöser stecken, könnte man wahrscheinlich die Java Namensauflöser biegen Sie die Typen, um herauszufinden,. DMS lassen Sie Bäume zusammenstellen, die Fragmente codieren entsprechen, und sie zu größeren verschmelzen; als Werkzeug Fakten für die Symboltabelle gesammelt, könnte es die primitiven Bäume bauen.

Irgendwo, müssen Sie entscheiden, Sie fertig sind. Wie viele Einheit testet das Werkzeug haben, um zu sehen bevor kennt er die gesamte Oberfläche? (Ich denke, es isst all die, die Sie zur Verfügung stellen?). Nach Fertigstellung assembliert sie die Fragmente für die verschiedenen Elemente und bauen eine AST für eine Schnittstelle; DMS kann seine Pretty verwenden, um diese AST zu konvertieren zurück in den Quellcode wie Sie gezeigt haben.

Ich schlage vor, Java hier, weil unser Java Frontend Namen und Typen Auflösung hat. Unser C # Frontend nicht. Dies ist eine „reine“ Angelegenheit des Ehrgeizes; hat jemand einen schreiben, aber das ist ziemlich viel Arbeit (zumindest war es für Java und ich kann nicht C # ist wirklich anders vorstellen).

Aber die Idee funktioniert im Prinzip DMS verwendet.

Sie können dies tun mit einer anderen Infrastruktur, gab man zu einem Parser zugreifen und ein einen biegsamen Namen und Typ-Resolver. Das mag nicht so einfach für C # zu erhalten; Ich vermute, MS kann Ihnen einen Parser und den Zugriff auf Namen und den Typ Auflösung, aber keine Möglichkeit, das zu ändern. Vielleicht Mono ist die Antwort?

Sie müssen noch eine war zu Codefragmente zu erzeugen und montieren. Sie könnten versuchen, dies durch Zeichenfolge tun Hacking; meine (lang) Erfahrung mit Zusammenkleben Programm Bits ist, dass, wenn Sie es mit Streichern tun Sie schließlich ein Chaos daraus machen. Sie wollen wirklich Stücke, die Code-Fragmente bekannter Art dar, die nur in einer Weise, die Grammatik erlaubt kombiniert werden können; DMS macht das also kein Durcheinander.

Andere Tipps

Es ist erstaunlich, wie niemand gab wirklich alles auf, was Sie fragen.

ich nicht die Antwort kennen, aber ich werde meine Gedanken geben.

Wenn ich versuchen, etwas zu schreiben, ich mich wahrscheinlich über einen ReSharper Plugin sehen würde. Der Grund, warum ich sage, dass liegt daran, wie Sie sagen, resharper es tun können, aber in einzelnen Schritten. So würde ich etwas schreiben, die Linie ging durch die Linie und angewandter die entsprechenden resharper Erstellungsmethoden miteinander verkettet.

Jetzt keineswegs weiß ich auch, wie dies zu tun, da ich nie etwas für resharper gebaut habe, aber das ist das, was ich versuchen würde, zu tun. Es macht logischen Sinn, dass es getan werden könnte.

Und wenn Sie einen Code schreiben auf, bitte per Post, wie ich auch, dass sehr nützlich finden konnte, in der Lage, das gesamte Skelett in einem Schritt zu erzeugen. Sehr nützlich.

Wenn Sie Ihre eigene Implementierung schreiben würde ich vorschlagen, auf jeden Fall, dass Sie bei der Geschwindigkeit (Java) Template-Engines.

Ich habe diese in einem Codegenerator vor und habe festgestellt, verwendet, dass sie die Arbeit sehr viel einfacher machen.

Es ist machbar - zumindest in der Theorie. Was ich tun würde, ist so etwas wie verwenden csparser die Unit-Test zu analysieren (Sie können es nicht kompilieren können, leider) und nehmen sie es dann von dort aus. Das einzige Problem, das ich sehen kann, ist das, was Sie tun in Bezug auf Methodik falsch ist - es macht mehr Sinn, Unit-Tests von Entitätsklassen zu erzeugen (in der Tat, Visual Studio tut dies genau) als um es anders zu tun

Ich denke, eine wirkliche Lösung für dieses Problem ein sehr spezieller Parser sei. Da das zu tun, nicht so einfach ist, habe ich eine billigere Idee. Leider würden Sie so, wie Sie Ihre Tests schreiben ändern müssen (nämlich nur die Erstellung des Objekts):

dynamic p = someFactory.Create("MyNamespace.Person");
p.Name = "Sklivvz";
Assert.AreEqual("Sklivvz", p.Name);

Ein Factory-Objekt verwendet werden würde. Wenn es das benannte Objekt finden kann, wird es schaffen und senden Sie es (das ist die normale Testausführung). Wenn es sie nicht findet, wird es eine Aufzeichnung Proxy erstellen (ein DynamicObject ), der alle Anrufe und am Ende aufnehmen wird (vielleicht auf abzureißen) Klassendateien vielleicht auf einigen Vorlagen emittieren könnte (basierend), das, was er „Säge“ genannt zu werden.

Einige Nachteile, die ich sehe:

  • Sie benötigen den Code in "zwei" Modi laufen, was ärgerlich ist.
  • Um für den Proxy zu „sehen“ und Anrufe aufzeichnen, müssen sie ausgeführt werden; so Code in einem catch Block, zum Beispiel, hat zu laufen.
  • Sie haben die Art und Weise ändern Sie Ihr Objekt im Test erstellen.
  • Sie haben dynamic zu verwenden; Sie verlieren in den folgenden Durchläufen Kompilierung-Sicherheit und Performance-Einbußen hat.

Der einzige Vorteil, den ich sehe, ist, dass es viel billiger zu erstellen, als ein spezialisierter Parser.

I CodeRush von DevExpress mag. Sie haben eine riesige anpassbare Template-Engine. Und das Beste für mich sie ist keine Dialogfelder. Sie haben auch Funktionen zum Erstellen Methoden und Schnittstellen und Klassen von der Schnittstelle, die nicht existieren.

Versuchen Sie, bei der Pex, eine Microsoft Project auf Unit-Tests suchen, die sich noch im Forschungs ist

research.microsoft.com/en-us/projects/Pex/

Ich denke, was Sie suchen ist ein Fuzzing-Tool-Kit (https://en.wikipedia.org/wiki/Fuzz_testing).

Al hart ich nie benutzt, könnte man Randoop.NET eine Chance geben 'Unit-Tests' zu erzeugen http: // randoop .codeplex.com /

Visual Studio kommt mit einigen Features, die für Sie nützlich sein können:

generieren Methode Stub . Wenn Sie einen Anruf auf ein Verfahren zu schreiben, die nicht existiert, werden Sie ein wenig Smart-Tag auf dem Methodennamen erhalten, die Sie eine Methode Stub zu erzeugen, auf der Basis der Parameter können Sie übergeben.

Wenn Sie eine Tastatur Person (Ich bin), dann direkt nach der geschlossenen Klammer eingeben, können Sie tun:

  • Strg -. (den Smart-Tag zu öffnen)
  • ENTER (die Stub zu erzeugen)
  • F12 (gehen Sie zu Definition, die Sie der neuen Methode zu nehmen)

Der Smart-Tag wird nur angezeigt, wenn die IDE denken, dass es keine Methode, die übereinstimmt. Wenn Sie generieren möchten, wenn die Smart-Tag nicht hoch ist, können Sie auf Bearbeiten-> Intellisense-> generieren Methode Stub .

Snippets . Kleine Code-Vorlagen, die es einfach zu erzeugen Bits von gemeinsamem Code macht. Einige sind einfach (versuchen "wenn [TAB] [TAB]"). Einige sind komplex ( ‚Schalter‘ werden Fälle für eine Enumeration erzeugen). Sie können auch Ihre eigenen schreiben. Für Ihren Fall versuchen „Klasse“ und „prop“.

Siehe auch „ Wie sich ändern„ gene~~POS=TRUNC Methode Stub“NotImplementedException in VS werfen? “ für Informationen Schnipsel im Kontext von GMS.

autoprops . Denken Sie daran, dass die Eigenschaften können viel einfacher sein:

public string Name { get; set; }

erstellen Klasse . In dem Solution Explorer RAuf auf den Projektnamen oder einen Unterordner, wählen Sie Add-> Klasse . Geben Sie den Namen der neuen Klasse. Hit ENTER . Hier finden Sie eine Klassendeklaration in dem richtigen Namensraum erhalten, etc.

Implement Interface . Wenn Sie eine Klasse wollen eine Schnittstelle implementieren, schreiben Sie den Namen der Schnittstelle Teil, aktivieren Sie den Smart-Tag, und entweder Option auswählen, um Stubs für die Schnittstellenelemente zu erzeugen.

Diese sind nicht ganz 100% automatisierte Lösung für Sie suchen, aber ich denke, es ist eine gute Milderung.

Ich finde, dass, wenn ich ein Code-Generierungs-Tool wie diese benötigt, ich wahrscheinlich Code schreibt, die ein bisschen mehr Generika gemacht werden könnte, so dass nur ich brauche es einmal zu schreiben. In Ihrem Beispiel scheinen diese Getter und Setter keinen Wert, um den Code zu Hinzufügen -. In der Tat ist es wirklich behauptet nur, dass der Getter / Setter-Mechanismus in C # Werken

Ich würde verzichten zu schreiben (oder sogar mit) ein solches Instrument vor zu verstehen, was die Beweggründe für diese Art von Tests zu schreiben sind.

BTW, möchten Sie vielleicht einen Blick haben unter NBehave ?

Ich benutze Rhino Mocks dafür, wenn ich brauche nur einen einfachen Stummel.

http://www.ayende.com/wiki/Rhino+ Mocks + - + Stubs.ashx

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