BDD - Expected Exceptions


Wie testet man auf eine erwartete Exception im BDD-Style?

Hier ein (etwas sinnfreies) Beispiel - auch hier das ganze wieder mit xUnit und den xUnitBddExtensions:

   1: [Concern(typeof (Television))]
   2: public class when_Television_gets_turnOff_command_if_it_is_turned_off : InstanceContextSpecification<Television>
   3: {
   4:     private Action theTurnOffAction;
   5:  
   6:     protected override Television CreateSut()
   7:     {
   8:         return new Television();
   9:     }
  10:  
  11:     protected override void Because()
  12:     {
  13:         theTurnOffAction = The.Action(() => Sut.TurnOff());
  14:     }
  15:  
  16:     [Observation]
  17:     public void Should_throw_an_NotYetTurnedOnException()
  18:     {
  19:         theTurnOffAction.ShouldThrowAn<NotYetTurnedOnException>();
  20:     }
  21: }

 

 

In Zeile 13

theTurnOffAction = The.Action(() => Sut.TurnOff());

wird ein Action-Delegate gespeichert, welches dann auf Zeile 19 im Hintergrund aufgerufen wird.

theTurnOffAction.ShouldThrowAn<NotYetTurnedOnException>();

Ein weiteres Beispiel für schön lesbare und somit aussagekräftige Tests.

 

Tags: ,

author: Dani | posted @ Sunday, January 04, 2009 1:06 AM | Feedback (0)

BDD - bin ich schon drin oder was?


Ich lese schon eine Weile bei Alt.Net (DE) mit. In letzter Zeit war da immer mal wieder das Thema von BDD (Behaviour Driven Design) als Evolution zu TDD (Test Driven Design). Nachdem ich einige Zeilen darüber gelesen habe, war mir klar, dass das eine genauere Betrachtung verdient hat.

Nachfolgender Artikel (und folgende) sollten nicht als Experten-Essay verstanden werden - vielmehr soll es Einsteigern helfen, die die gleichen Fehlüberlegungen machen und sich in die gleichen Sackgassen verrennen wie ich. Natürlich wär's auch schön, wenn ich von dem einen oder anderen Experten einen Schubs in die richtige Richtung erhalten würde. :-)

Aber worum gehts denn nun überhaupt:

 

TDD, BDD... WTF?

Wie bereits gesagt, ist BDD als Evolution und nicht etwa als Alternative zu TDD zu verstehen. Kurz gesagt: TDD stellt den Test in den Mittelpunkt, BDD das Verhalten (Behaviour). Auf den ersten Blick erscheinen BDD-Tests recht speziell. Die Klassen- und Test-Namen sind in sprechender Form gehalten. Das ist dann auch gleich einer der Hauptpunkte von BDD: die Sprache. BDD-Tests sollen in einer Sprache definiert sein, die auch ein Fach-Vertreter lesen und verstehen kann.

 

Hands On

Hier mal ein Beispiel: eine Klasse "Television" soll getestet werden. Es wird das Verhalten getestet, wenn der Fernseher eingeschaltet wird.

Für das Beispiel wurde xUnit mit den xUnitBddExtensions von Björn Rochel verwendet. Diese beiden Frameworks erlauben es, den BDD-Gedanken bestmöglichst in Code umzusetzen.

   1: [Concern(typeof (Television))]
   2: public class when_Television_turns_on : InstanceContextSpecification<Television>
   3: {
   4:     protected override Television CreateSut()
   5:     {
   6:         return new Television();
   7:     }
   8:  
   9:     protected override void Because()
  10:     {
  11:         Sut.TurnOn();
  12:     }
  13:  
  14:     [Observation]
  15:     public void Should_start_on_channel_one()
  16:     {
  17:         Sut.GetCurrentChannel().ShouldBeEqualTo(1);
  18:     }
  19:  
  20:     [Observation]
  21:     public void Should_allow_to_turn_off()
  22:     {
  23:         Sut.TurnOff().ShouldBeTrue();
  24:     }
  25: }

Die Basisklasse InstanceContextSpecification<T> wird vom xUnitBddExtensions-Framework bereitgestellt.

In CreateSut (Sut = System under test), wird also die zu testende Instanz erstellt. Because stellt dann also den eigentlichen Grund des Testens dar, in diesem Falle also die TurnOn-Methode. Danach folgen zwei Observations, die eigentlichen Tests.

Wenn man sich nun die Resultate in einem Testrunner anschaut, sieht man auch, wie sprechend das ganze jetzt daher kommt:

 

03.01

So ein Bericht kann man gut auch jemandem von Fach vorlegen, ohne dass dieser die Stirn runzelt - ok, wenn noch alles rot ist so wie hier, vielleicht schon :-)

Was man auch schön sieht ist, dass sich dieser Bericht wie das Inhaltsverzeichnis einer Spezifikation liest. Die Tests sind also viel näher bei den Anforderungen - auch sprachlich. Mein Eindruck war auch, dass sich Tests so einfacher identifizieren lassen.

 

AAA

Und gleich nochmal so ein TLA ;-) AAA steht für "Arrange Act Assert" und stellt ein Syntax-Pattern dar. In unserem Beispiel wurde der Test in genau drei solche Teile zerlegt:

  1. CreateSut (= Arrange)
  2. Because (= Act)
  3. Should_x (= Assert)

Der Vorteil dieser Syntax ist, dass die verschiedenen Bereiche des Tests sauber voeinander getrennt sind - so können die Observations auf das wirklich Wesentliche (nämlich das Testen der Verhalten) reduziert werden.

Ansatzweise ist das auch in den bekannten TestSetup-Verfahren von nUnit & Co. umgesetzt - allerdings wird dort das Act und Assert meist vermischt. Die xUnitBddExtensions erlauben hier eine schöne Trennung und saubere Syntax.

 

Das war ein erster kleiner Einblick in BDD, welcher hoffentlich zum Einstieg einlädt. Ich kann es nur empfehlen. Wer damit starten möchte, dem möchte ich nochmals die xUnitBddExtensions wärmstens ans Herz legen. Die Sourcen umfassen neben dem Framework auch noch zwei Templates für Resharper, welche die Test-Erstellung erleichtert. Ausserdem wurden die Extensions selbst mit BDD-Tests getestet, das heisst man hat dort schon jede Menge guter Samples drin.

Tags: ,

author: Dani | posted @ Saturday, January 03, 2009 11:38 PM | Feedback (1)

Ohne Worte


Taskman

Nein, kein 8-Core, aber zumindest 4 mit Hyperthreading - Core i7 machts möglich 

author: Dani | posted @ Saturday, December 06, 2008 11:36 AM | Feedback (0)

Mehrspaltige DropDownList / ListBox


Eine doch lästige und unschöne Einschränkung bei der DropDownList ist doch, dass man nur ein Feld der DataSource an das Control binden kann.

Oft will man halt aber mehr als nur ein Feld darstellen:

Kategorie A: 3 Fahrzeuge

Kategorie B: 11 Fahrzeuge

Kategorie C: 1 Fahrzeug

Natürlich geht das relativ problemlos, z.B. mittels String-Concatenation, ist aber doch lästig, wenn man sonst alles schön über direktes DataBinding lösen könnte – zumal das Control ja auch einen FormatString zur Steuerung der Ausgabe entgegennimmt.

Eine Ableitung der DropDownList zu bauen, die das kann, ist zum Glück keine Kunst. Nachfolgend das Beispiel mit einer DropDown-List, die ListBox verhält sich analog.

Zuerst erstellt man sich also eine Klasse, die von DropDownList erbt:

   1: public class MultiColumnDropDownList : DropDownList

 

Die DropDownList nimmt den Namen des anzuzeigenden DataSource-Feldes im Property DataTextField auf. Ich benutze das Property gleich auch für meine Zwecke, lasse aber mehrere Angaben, getrennt durch ein Semikolon zu.

Die einzige Methode dies es dann zu überschreiben gilt ist PerformDataBinding. Dort kriegt man als Parameter die DataSource praktisch als IEnumerable.

   1: protected override void PerformDataBinding(System.Collections.IEnumerable dataSource)

Die eigentliche Implementation ist dann denkbar simpel:

   1: foreach (Object obj in dataSource)
   2: {
   3:     string[] textFieldsValues = new string[textFields.Length];
   4:     for (int i = 0; i < textFields.Length; i++)
   5:     {
   6:         textFieldsValues[i] = DataBinder.GetPropertyValue(obj, textFields[i].Trim()).ToString();
   7:     }
   8:  
   9:     ListItem li = new ListItem();
  10:     li.Text = string.Format(list.DataTextFormatString, textFieldsValues);
  11:     li.Value = DataBinder.GetPropertyValue(obj, list.DataValueField);
  12:     list.Items.Add(li);
  13: }

In Zeile 6 wird mittels der DataBinder-Klasse der Wert aus der DataSource gelesen. Hat den Vorteil, dass man sich nicht darum kümmern muss, was denn nun für eine DataSource dahinter steckt. Der Rest ist wohl selbsterklärend.

Eingebunden in einer aspx-Seite sieht dann das so aus:

   1: <NN:MultiColumnDropDownList  ID="ddlMulti" runat="server" 
   2:             DataSourceID="ObjectDataSource1" DataTextField="Name;PreName" 
   3:             DataValueField="Id" DataTextFormatString="{0} {1}" />

Und als Ausgabe:

greenshot_2008-10-02_20-38-46

Download der Sourcen

author: Dani | posted @ Thursday, October 02, 2008 8:49 PM | Feedback (0)

Herrlich! Göttlich!


Leider hört man ja von Maradona eigentlich selten noch erfreuliches, das soll aber nicht daran hindern, sich an alten Perlen zu erfreuen. Auf so eine bin ich heute im Schweizer Schundblatt Nr. 1 gestossen:

Da ist sogar das Einspielen ein Highlight!

Perfekte Einstimmung für heute Abend, wenn der FC Zürich, zwar kaum so brilliant, aber hoffentlich mit viel Kämpferherz die Milanesi rauskickt. :-)

author: Dani | posted @ Thursday, October 02, 2008 6:29 PM | Feedback (0)

Private Methoden mit UnitTests testen


Das Testen von privaten Methoden wirft immer wieder Fragen auf. Natürlich gibt es hierfür auch diverse Lösungen:

  • Visual Studio erstellt einen sogenannten Private Accessor, was schlussendlich nichts anderes als ein Wrapper ist, der mittels Reflection auf die privaten Members zugreift.
    Das ganze ist mir eher unsympathisch und verkompliziert das ganze nur. Ausserdem entstehen Schwierigkeiten beim Mocking. Trotzdem war dies bis jetzt die Lösung meiner Wahl.
    TestReference
  • Private Members gar nicht testen. Da private Methoden in der Regel irgendwo mal aufgerufen werden, kann man diese über Tests von öffentlichen Methoden abhandeln. Mittels CodeCoverage lässt sich überwachen, dass die Methoden auch wirklich getestet werden. Nur wiederspricht das natürlich klar den Gesetzen von UnitTests.
  • Natürlich kann man sich auch etwas eigenes bauen, um mittels Reflection an die Methoden zu kommen.
    Neben dem Aufwand birgt das natürlich auch Fehlerpotential – und Fehler in Tests sind eher doof :-)

Alles also irgendwie ok – aber halt doch nicht so. Heute bin ich aber über zwei Klassen gestossen, mit denen man das Problem doch recht einfach lösen kann: PrivateObject und PrivateType.

Und so siehts aus:

   1: string name = "Dani";
   2: string expected = "Hello Dani";
   3:  
   4: MyClass mc = new MyClass();
   5: PrivateObject po = new PrivateObject(mc);
   6: string actual = po.Invoke("SayHello", name).ToString();

 

Und für statische Methoden nimmt man einfach PrivateType:

   1: PrivateType pt = new PrivateType(typeof(MyClass));
   2: string actual = pt.InvokeStatic("SayBye", name).ToString();

author: Dani | posted @ Tuesday, September 30, 2008 9:29 PM | Feedback (5)

nettigkeiten.ch goes Mobile!


Dank der MobileFeeds-Applikation meines früheren Arbeitgebers Connvision kann mein Blog nun auch komfortabel auf einem Mobile-Phone gelesen werden (mit entsprechend angepasster Darstellung).

mobilefeeds

Als Leckerli erhält man bei MobileFeeds auch gleich einen BeeTagg der auf den Mobile-Feed linkt. Die Software die man benötigt, um den BeeTagg zu lesen kriegt man hier oder auch über Wap-Push (weitere Infos: beetagg.com).

Ist der Reader erst installiert, kann man den untenstehenden BeeTagg lesen und wird auf den MobileFeed geleitet.

 

beetagg.nettigkeiten

 

Hier noch eine kleine Demo wie kinderleicht das mit dem BeeTagg scannen so funktioniert:

author: Dani | posted @ Friday, July 25, 2008 12:22 AM | Feedback (0)

Restaurant-Tip: Focacceria, St. Gallen (CH)


Ein kleines Novum hier im Blog. Ab und an will ich in Zukunft auf, meiner Meinung nach, besonders erwähnenswerte Restaurants hinweisen. Ich verstehe dies auch als kleine Belohnung für die jeweilige Crew, welche sich abgemüht hat, meiner Begleitung und mir einen schönen Abend zu ermöglichen. Schliesslich gibt es ja leider genug andere Beispiele.

Wer die Focacceria betritt, wird von einer warmen, etwas rustikalen und trotzdem modern angehauchten Atmosphäre empfangen. Im Erdgeschoss ist quasi der Imbiss-Bereich – wobei dies einen etwas negativen Touch hat, der hier wahrlich nicht angebracht ist.
Im hinteren Bereich erwartet einen dann eine Theke voller mediteraner Köstlichkeiten, welche einem direkt an einen italienischen Feinkosthändler erinnert. Da reihen sich feinste Antipasti neben selbstgemachten Pasten (z.B. Oliven) ein. Die Stars der Theke sind aber die x verschiedenen Käsesorten sowie de grosse Auswahl an verschiedenen Leckereien für den Fleischesser. Hier darf man nun also sein eigenes Focaccia zusammenstellen. Es gibt drei verschiedene Grössen, wobei zumindest ich für das Grösste schon einen rechten Hunger brauche. Dann kann man sich eine Fleisch- oder Käsesorte auswählen, zwei Antipasti sowie eine Paste. Salat (z.B. Ruccola) gibt’s gratis. Das Fleisch wird frisch angeschnitten und mit den anderen Zutaten in das erwärmte Focaccia gepackt. Nun noch ein prickelnd frisches Gazosa dazu, und die Ferien-Stimmung ist perfekt.

  

(Bild focacceria.ch)

Wer sich die schmale Treppe nach oben getraut, findet dort ein etwas eleganter aufgemachtes kleines Restaurant. Der obere Stock ist bedient. Man kann dort, neben den Focaccias auch von einer sehr kleinen aber feinen Karte aussuchen. Die Karte wird täglich geändert und offeriert einem gluschtige Tagliatelle, Suppen und Salate. Nach dem Essen sollte man sich unbedingt auf einen Dolci-Vorschlag der Bedienung einlassen, da gibt’s wirkliche Leckereien darunter.

Alles in allem ein wirklich gelungenes Lokal welches die totale Italianità versprüht. Die Preise sind zwar nicht ganz ohne, aber dafür erhält man auch wirklich qualitativ hervorragende Lebensmittel sehr gut zubereitet.

(Bilder focacceria.ch)

Die Focacceria befindet sich an der Metzgergasse 22, 9000 St. Gallen.

 


author: Dani | posted @ Tuesday, July 22, 2008 9:22 PM | Feedback (0)

Alles neu!


Tattaaa! Happy New Year! Der erste Post 2008! Naja... ist ja erst Mitte Jahr

Die üblichen Entschuldigungen spar ich mir mal und konzentrier mich hier lieber auf die wichtigen Sachen. Ich habe mich, wie so manche andere auch in letzter Zeit, von dasBlog verabschiedet und mich für SubText entschieden.

Die Umstellung war recht harzig und mühsam und mit diversen Stolpersteinen versehen. Aber zum Glück gibts ja nette Leute die ihre Erfahrungen der Öffentlichkeit hinterlassen. Allen voran sei hier Oren Eini erwähnt, der sogar das UrlRewriting von SubText erweitert hat, so dass auch die meisten alten dasBlog-Links noch funktionieren sollten.

Solltet ihr trotzdem etwas nicht finden, dass noch nicht funktioniert, wär ich um eine kurze Meldung dankbar.

Auch wenn die alten Links dank Oren noch funktionieren sollten, passt eure Einstellungen doch trotzdem bitte auf die neue URL http://blog.nettigkeiten.ch an.

Schon komisch... da gibt's ein halbes Jahr lang kein Lebenszeichen, und kaum muss ich ins Militär, gibt's grad einen Relaunch... Naja, mal schauen, je nach Lage an der Front reichts dann vielleicht auch noch gleich für ein bisschen "anmalen".

author: Dani | posted @ Thursday, July 17, 2008 11:06 PM | Feedback (0)

Adventskalender bei entwickler-press.de


Heute schiessen ja die Adventskalender auf den verschiedensten WebSites geradezu aus dem Boden. Einer, dessen Besuch sich wirklich lohnt, ist auf entwickler-press.de zu finden. Dort gibts nämlich jeden Tag ein eBook gratis und franko zum Download, ja man muss sich noch nicht mal registrieren.

Heute gibts Managed Direct X und C#.

author: Dani | posted @ Saturday, December 01, 2007 2:22 PM | Feedback (0)