Dieser Artikel wurde maschinell übersetzt.

Programmiererpraxis

Kennenlernen von NSpec

Ted Neward

Ted NewardLeser meiner Kolumne werden wissen, dass man die Mechanismen, die ich benutzen gern zu erkunden oder eine neue Technologie zu demonstrieren (Bibliothek oder auf andere Weise) ist, was ein Kollege einmal als "Exploration Test" beschrieben: eine Suite von Unit-Tests entwickelt, nicht um die Technologie zu testen, aber es zu erkunden. Es erlaubt mir — der Entwickler/Nutzer — um einige Annahmen zu überprüfen, ich über die Technologie mache. Noch wichtiger ist, es gibt mir eine Regression-Suite, wenn eine neue Version von ausgeführt, dass Technologie rauskommt, damit wenn die neue Version eine Art kritische unterbrechende Änderung macht, ich es sofort erfahren können, und nicht nachdem ich das Upgrade gemacht (und hatte um die unterbrechende Änderung zur Laufzeit umgeben im Zusammenhang mit meinem Programm zu entdeckenanstatt viel leichtere Rahmen eine Testsuite).

Zum Thema testen jedoch es gibt einige angst und Bestürzung in der Gemeinschaft "Modi" zu testen: Unit-Tests gegenüber testgetriebene Entwicklung (TDD) versus verhaltensgesteuerte Development (BDD), in der Regel mit viel schreien und Schreien begleitet. Wegen der religiösen Natur solcher Diskussionen, habe ich dazu neigten, diesen Gegenstand zu vermeiden, aber ich habe vor kurzem (als Teil der Tat etwas Forschung für diese Spalte in der Tat), ein Test-Tool entdeckt — NSpec — das kommt von der BDD-Masse. Unabhängig davon, wie viel Sie mögen oder nicht mögen den BDD-Ansatz zu testen ist NSpec einen Besuch Wert.

Erste Schritte

Wie bei so vielen anderen Microsoft .NET Framework Pakete, erste Schritte mit NSpec ist heutzutage NuGet "Paket installieren" Befehl entfernt. Als Trojanisches Pferd dafür, zunächst erstellen einer Klassenbibliothek-Lösung (in c#, weil sie dem Stein-Papier-Schere-echse, Spock-Wettbewerb, die gewonnen ich hatte zwischen it, f# und Visual Basic Rechte zu den Code zu testen), eine Umgekehrte Polnische Notation (RPN)-Calculator-Klasse zu bauen, dass ich "NiftyCalc" aus Mangel an etwas origineller nenne. NiftyCalc wird ein bisschen wie ein abweichendes aus traditionellen RPN-Rechner, jedoch meist so habe ich etwas ein wenig komplexer testen können.

Ich werde mit nackte Knochen Grundlagen beginnen. Nach dem Erstellen eine neue Lösung und Klassenbibliothek-Projekt in Visual Studio, werde ich eine einfache Klasse zu erstellen, die eine einzelne, automatisch generierte Eigenschaft Mitglied namens Strom, entsprechend den aktuellen Wert im Speicher des Rechners gehalten hat:

namespace Calculator
{
  public class NiftyCalc
  {
    public NiftyCalc()
    {
      Current = 0;
    }
    public int Current { get; set; }
  }
}

Es ist nicht viel, aber es gibt genug Gerüste zu NSpec installiert, so dass ich die Anfänge der Verwendung es betrachten kann.

Nachdem ich die "Install-Package Nspec" in der Paket-Manager -Konsole, werden ein paar Dinge erschienen sind. Zuerst fügt NSpec einer anderen Datei dem Klassenbibliothek-Projekt namens DebuggerShim.cs. Ich will sehr ins Detail darauf jetzt nicht, aber es erlaubt die Ausführung NSpec Tests über TDD und ReSharper, zusammen mit Bereitstellung für die kontinuierliche Integration. Noch wichtiger ist, NSpec noch kein Standalone-Projekt als ein Peer-to-Klassenbibliothek-Projekt erstellt, wie ein standard Microsoft Test oder NUnit Test-Szenario würde — die Absicht ist es, dass NSpec testet (oder, wie das Unternehmen lieber nennen, Spezifikationen) Leben im gleichen Projekt wie der Code, die sie angeben sind.

Was bedeutet dann, dass um einen Test, um diese Prüfung zu erstellen, können Sie nur eine Klasse, die die Basisklasse "Nspec" erweitert:

using NSpec;
namespace Calculator
{
  class my_first_spec : nspec
  {
    void given_the_world_has_not_come_to_an_end()
    {
      it["Thunderhorse should be Thunderhorse"] =
        () => "Thunderhorse".should_be("Thunderhorse ");
      }
  }
  // ... 
          }

Das ist eindeutig ein traditionelles Unit Test nicht: Es fehlt der benutzerdefinierten Attribut-Tags; die Namenskonvention hat diese Unterstriche drin; Es gibt eine Art von String-Lambda-Wörterbuch hier am Werk ("it"); und alles ist im wesentlichen privat/intern. Um weitere Dinge deutlich anders vorzunehmen, NSpec ein neues Test-Runner-Tool in den Pfad innerhalb der Paket-Manager -Konsole installiert, und das ist, wo Sie abbiegen, um die Tests auszuführen. Führen Sie in der Paket-Manager -Konsole (die erinnern, im Grunde eine Windows PowerShell -Konsole in Visual Studioausgeführt wird), NSpecRunner.exe durch den vollständigen Pfad der kompilierte Klassenbibliothek:

PM> install-package nspec
Successfully installed 'nspec 0.9.65'.
          Successfully added 'nspec 0.9.65' to Calculator.
          PM> NSpecRunner.exe .
          \Calculator\bin\debug\Calculator.dll
my first spec
  given the world has not come to an end
    Thunderhorse should be Thunderhorse
1 Examples, 0 Failed, 0 Pending
PM>

Jetzt werden die ungeraden Namenskonventionen klar: NSpec ist mithilfe von Reflektion, um die Klassen und Methoden im Rahmen der Testsuite ausgeführt zu entdecken, und es verwendet die Unterstriche in den Namen als Räume, wenn die Ausgabe zu drucken. Die Absicht hier ist man mehr natürliche -­Sprache-ähnliche Syntax, so dass ich in "Meine erste Spec" schreiben können, gibt es eine Spezifikation, die "angesichts die Welt hat nicht zu einem Ende kommen, sollte Thunderhorse Thunderhorse"; so lange der Zusammenhang mit den letzten Teil der Spezifikation Lambda-Ausdruck den Wert True ausgibt, ist alles gut. Sollte der Spec/Test werden leicht so geändert, dass die beiden Zeichenfolgen gleich sind nicht, NSpecRunner geben eine andere Ausgabe (wie jeder Test Runner würde), siehe Abbildung 1.

Abbildung 1-Test mit zwei ungleichen Zeichenfolgen

PM> NSpecRunner.exe .
          \Calculator\bin\debug\Calculator.dll
my first spec
  given the world has not come to an end
  Thunderhorse should be Thunderhorse - FAILED - Expected string   length 12 but was 6.
          Strings differ at index 1.,   Expected: "Thunderhorse", But was: "Hello ", -----------------^
**** FAILURES ****
nspec.
          my first spec.
          given the world has not come to an end.
          Thunderhorse should be Thunderhorse.
          Expected string length 12 but was 6.
          Strings differ at index 1., Expected: "Thunderhorse", But was: "Hello ", -----------------^
   at Calculator.my_first_spec.<Thunderhorse_should_be_Thunderhorse>b__2() in        c:\Projects\Publications\Articles\MSDN\WorkingProg\NSpec\NSpec\   Calculator\   Class1.cs:line 19
2 Examples, 1 Failed, 0 Pending
PM>

Wie abgeleitet werden könnte, ist der tatsächliche "test" Teil der Spezifikation die Should_be Erweiterungsmethode, die NSpec an irgendwas einführt, die von System.Object abgeleitet ist. Darüber hinaus gibt es eine Reihe von ähnlich benannten Überladungen auf der Idee, so dass wenn Sie möchten sicherstellen, dass 2 + 2 größer als 3 ist, können Sie die Should_be_greater_than-Methode stattdessen verwenden. Ein weiteres halbes Dutzend oder so Überladungen der ähnlicher Weise stehen; Jeder kennt jeden Komponententest-Rahmen sollte mit diesen bequem sein.

Ein Nachteil NSpec, mindestens die Version (0.95), die ich getestet habe, ist, dass NSpec mit Visual Studiointegriert ist nicht so, dass Sie nicht nur drücken Sie F5, und Build/ausführen Projekte; Stattdessen müssen Sie explizit die Bibliothek zu bauen, dann finden die Paket-Manager -Konsole und oben auf die NSpecRunner-Linie, Kick-off der Tests. Die Website NSpec.org bietet eine Lösung an, genannt Specwatchr, die ein Ruby-Skript, die hält ein Auge auf die Dateien im Verzeichnis und NSpecRunner startet, wenn eine Quelldatei gespeichert wird. Obwohl ich es nichts ausmacht, schaltet einige Entwickler und einige Geschäfte ihre Nase am Installieren von Ruby-Plattform nur um haben diese Funktionalität, nützlich, da es sein kann. Ich persönlich glaube, welcher Abneigung, die Sie möglicherweise für die Installation von Ruby auf Ihrem Rechner enorm ausgeglichen wird, indem man ein Tool, das automatisch ausführen der Tests wie diese, vor allem, weil es sich bewährt hat eine sehr nützliche Technik in anderen Umgebungen Sprache und Plattform mit dem .NET Framework als einsamer Contrarian in diesem Punkt. Ich empfehle die Zeit nehmen, es geben einen Wirbel — in einer virtuellen Maschine (VM), die dir egal, wenn es sein muss.

Testen NiftyCalc

In der Zwischenzeit mit einigen der NSpec Grundlagen aus dem Weg, kann ich mich wenden, wodurch einige Tests um NiftyCalc und erweitern es. Zunächst einmal möchte ich sicherstellen, dass bei der Erstellung einer NiftyCalc den aktuellen Inhalt bei 0 beginnen; Wenn ich eine Zahl auf dem NiftyCalc-Stapel schieben, ist diese Zahl was aktuell angezeigt wird; und wenn ich eine Zahl drücken, drücken Sie eine andere Nummer und pop im Stapel, die erste Zahl wird beibehalten, wie in Abbildung 2.

Abbildung 2 Testen NiftyCalc Funktionalität

using NSpec;
namespace Calculator
{
  class nifty_calc : nspec
  {
    void calculator_basics()
    {
      it["New NiftyCalc should have a Current of 0"] =
        () => new NiftyCalc().Current.should_be(0);
      it["Pushing 5 should show Current as 5"] =
        () =>
        {
          NiftyCalc nc = new NiftyCalc();
          nc.Push(5);
          nc.Current.should_be(5);
        };
      it["Push, push, pop, should have Current set to first pushed value"] =
        () =>
        {
          NiftyCalc nc = new NiftyCalc();
          nc.Push(5); nc.Push(7); nc.Pop();
          nc.Current.should_be(5);
        };
      }
    }
  public class NiftyCalc
  {
    private Stack<int> theStack = new Stack<int>();
    public NiftyCalc()
    {
      theStack.Push(0);
    }
    public int Current
    {
      get { return theStack.Peek(); }
    }
    public void Push(int value)
    {
      theStack.Push(value);
    }
    public int Pop()
    {
      return theStack.Pop();
    }
  }
}

So weit, so gut. In der Tat ist es fast überflüssig, in Prosa den Test beschreiben ich möchte schreiben, dann zeigen den Code für den Test, weil die sehr Syntax der NSpec testen Registrierung (die "It" Instanz innerhalb der NSpec abgeleitete Klasse) wirklich ermöglicht so ausführlich oder als knappe eine Beschreibung wie ich möchte. Dies ist, wie bereits von Design, erwähnt, so dass Tests und Spezifikationen leicht sind zu lesen und zu verstehen —, die, wenn man bedenkt wie oft Suites testen sind als Dokumentation in diesen Tagen, ist etwas wertvolles.

Exceptions

Natürlich gibt es auch die Frage der mitunter Rand zu prüfen: Was geschehen soll, falls einen Benutzer versucht, eine mehr Wert aus der NiftyCalc als jemals geschoben wurde pop? Es ist ein häufiges Problem mit stapeln, aber NiftyCalc ist nicht versucht einen Stapel, sondern eher eine funktionale Rechner zu sein. Zu diesem Zweck sollten die Pop-Methode und die Current-Eigenschaft Get-Methode überprüfen, um zu sehen, ob es etwas im Stapel abrufen, und wenn nicht, einen Wert von NULL liefern.

Allerdings sollte das Geschäft lieber, dass NiftyCalc eine Ausnahme werfen, beim Auftauchen eines leeren Stacks, der NSpec Code überprüfen kann, die, so wie:

it["Should throw a NullRef if the NiftyCalc is null"] =
  expect<NullReferenceException>( () => {
    NiftyCalc nc = null;
    nc.Push(5);
  });

Wieder ist dies weit entfernt aus wie ein Komponententest-Rahmen (z. B. Microsoft-Test-Manager oder NUnit) aussieht.

Context

Übrigens gibt es auch eine ganze Menge Wiederholung mit den vorhergehenden Code NSpec; Es wäre schön, wenn Sie ein "Kontext", in dem der Test ausgeführt wird, einrichten könnte, damit Sie nicht ständig die NiftyCalc und drücken Sie ein paar Werte, um zu testen. (Dies ist in den nachfolgenden Tests, von unschätzbarem Wert, denn ich will die Funktionalität Ihres hinzufügen, subtrahieren und so weiter.) NSpec können Sie solchen Kontext zu erstellen, wie in Abbildung 3.

Abbildung 3 Einrichten eines Testkontexts

using NSpec;
namespace Calculator
{
  class nifty_calc : nspec
  {
    void calculator_basics()
    {
      // ... 
            void before_each()
      {
        Calc = new NiftyCalc(); //maybe move this line here
      }
      context["When NiftyCalc has a 2 and 3 pushed"] = () =>
      {
        before = () =>
        {
          calc.Push(3);
          calc.Push(2);
        };
        it["should Add to 5"] = () =>
        {
          calc.Add();
          calc.Current.should_be(5);
        };
        it["should Subtract to 1"] = () =>
        {
          calc.Subtract();
          calc.Current.should_be(1);
        };
      };
    }
    private NiftyCalc calc;
  }
  public class NiftyCalc
  {
    private Stack<int> theStack = new Stack<int>();
    public NiftyCalc() { }
    public int Current
    {
      get { return (theStack.Count != 0) ? 
            theStack.Peek() : 0; }
    }
    public void Push(int value) {
      theStack.Push(value);
    }
    public int Pop() {
      return (theStack.Count != 0) ? 
         theStack.Pop() : 0;
    }
    public void Add() { Push(Pop() + Pop()); }
    public void Subtract() { int top = Pop();     
    int bot = Pop(); Push(bot - top); }
  }
}

Dieser Test zeigt auch, wie zu Verwendung von "vorher" Haken, jeder einzelne Test-Übung vor der Ausführung einrichten — das gibt Ihnen die Möglichkeit, die NiftyCalc-Instanz erstellen und schieben Sie zwei Werte darauf vor Übergabe es nach Beginn des Tests für die Ausführung.

Zunehmende Nutzung

Es gibt eine ganze Reihe mehr über NSpec — und das größere Thema BDD — darüber hinaus, was hier diskutiert worden ist, aber das wird einige der Grundlagen im Spiel. BDD-Enthusiasten werden kritisieren, die Stil und Ansatz zum Schreiben von meinen Tests habe ich getroffen, aber das ist eine stilistische und ästhetische Debatte möchte ich weder Teilnahme noch versuchen, die in diesem Artikel zu erfassen. NSpec selbst ist ein interessanter Ansatz zu testen – und noch wichtiger ist, eine Komponente, die in immer mehr erscheint open-Source-Projekte. Wenn Sie mehr über NSpec erfahren möchten, hat freundlicherweise Amir Rajan, Mitentwickler des Rahmens, freiwillig, beantworten Fragen und geben Hinweise. Sie erreichen ihn auf Twitter bei twitter.com/amirrajan oder seine GitHub-Website unter github.com/amirrajan.

Viel Spaß beim Programmieren!

Ted Neward ist der Geschäftsinhaber von Neward & Associates LLC. Er hat mehr als 100 Artikel geschrieben und Autor und Mitautor von einem Dutzend Bücher, darunter "professionelle f# 2.0" (Wrox, 2010). Er ist ein F#-MVP und spricht auf Konferenzen auf der ganzen Welt. Er berät und Mentoren regelmäßig — erreichen ihn bei ted@tedneward.com Wenn Sie daran interessiert, ihn zusammen mit Ihrem Team, oder lesen Sie seinen Blog unter blogs.tedneward.com.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Amir Rajan (Verbesserung der Unternehmen)