Like the TDD principle “Write the tests first†we should write our spec first and use the “Red-Green-Refactor†method.
"Red" – Create a spec scenario that fails
At first I created a F# class library project called “Spec.CarSelling†and added project references to NaturalSpec.dll and nunit.framework.dll (see “Getting started†for further explanations).
Now I can write my first scenario:
// 1. define the module
module CarSpec
// 2. open the NaturalSpec namespace open NaturalSpec
// 3. open project namespace
open CarSellingLib
// 4. define a test context
let Bert = new Dealer("Bert")
// 5. create a method in BDD-style
let selling_a_car_for amount (dealer:Dealer) =
printMethod amount
dealer.SellCar amount
// 6. create a scenario
[<Scenario>]
let When_selling_a_car_for_30000_it_should_equal_my_DreamCar() =
As Bert
|> When selling_a_car_for 30000
|> It should equal (new Car(CarType.BMW, 200))
|> Verify
At this stage the scenario is ready but doesn’t compile. This means we are ready with the "Red"-stage.
"Green" – Make the test the pass
In order to get the test green we have to create a C# class library called CarSellingLib and define the enum CarType and the classes Dealer and Car. Sticking to the YAGNI-principle we implement only the minimum to get the spec green (and ToString()-members for the output functionality).
namespace CarSellingLib
{
public enum CarType
{
BMW
}
}
namespace CarSellingLib
{
public class Car
{
public Car(CarType type, int horsePower)
{
Type = type;
HorsePower = horsePower;
}
public CarType Type { get; set; }
public int HorsePower { get; set; }
public override string ToString()
{
return string.Format("{0} ({1} HP)", Type, HorsePower);
}
public override bool Equals(object obj)
{
var y = obj as Car;
if(y == null) return false;
return Type == y.Type && HorsePower == y.HorsePower;
}
}
}
using System;
namespace CarSellingLib
{
public class Dealer
{
public Dealer(string name)
{
Name = name;
}
public string Name { get; set; }
public Car SellCar(int amount)
{
return new Car(CarType.BMW, 200);
}
public override string ToString()
{
return Name;
}
}
}
When we add a project reference to our spec-project the UnitTests should pass and we have completed the "Green" step. (See "Getting started" if you don’t know how to run the spec.) Now we can add some more scenarios to our spec:
// 1. define the module module CarSpec
// 2. open NaturalSpec-Namespace
open NaturalSpec
// 3. open project namespace
open CarSellingLib
// 4. define a test context
let Bert = new Dealer("Bert")
// define reusable values
let DreamCar = new Car(CarType.BMW, 200)
let LameCar = new Car(CarType.Fiat, 45)
// 5. create a method in BDD-style
let selling_a_car_for amount (dealer:Dealer) =
printMethod amount
dealer.SellCar amount
// 6. create a scenario
[<Scenario>]
let When_selling_a_car_for_30000_it_should_equal_the_DreamCar() =
As Bert
|> When selling_a_car_for 30000
|> It should equal DreamCar
|> It shouldn't equal LameCar
|> Verify
[<Scenario>]
let When_selling_a_car_for_19000_it_should_equal_the_LameCar() =
As Bert
|> When selling_a_car_for 19000
|> It should equal LameCar
|> It shouldn't equal DreamCar
|> Verify
// create a scenario that expects an error
[<Scenario>]
[<Fails_with "Need more money">]
let When_selling_a_car_for_1000_it_should_fail_with_Need_More_Money() =
As Bert
|> When selling_a_car_for 1000
|> Verify
Now we are in the “Redâ€-Phase again.
"Refactor" – rearrange your code to eliminate duplication and follow patterns
After making the spec "Green" and doing some refactoring the project code could look like this:
namespace CarSellingLib
{
public enum CarType
{
Fiat,
BMW
}
}
namespace CarSellingLib
{
public class Car
{
public Car(CarType type, int horsePower)
{
Type = type;
HorsePower = horsePower;
}
public CarType Type { get; set; }
public int HorsePower { get; set; }
# region ToString, Equals
public override string ToString()
{
return string.Format("{0} ({1} HP)", Type, HorsePower);
}
public override bool Equals(object obj)
{
var y = obj as Car;
if(y == null) return false;
return Type == y.Type && HorsePower == y.HorsePower;
}
#endregion
}
}
using System;
namespace CarSellingLib
{
public class Dealer
{
public Dealer(string name)
{
Name = name;
}
public string Name { get; set; }
public Car SellCar(int amount)
{
if (amount > 20000)
return new Car(CarType.BMW, 200);
if (amount > 3000)
return new Car(CarType.Fiat, 45);
throw new Exception("Need more money");
}
public override string ToString()
{
return Name;
}
}
}
The spec output should look like the following:
Scenario: When selling a car for 1000 it should fail with Need More Money
– Should fail…
– As Bert
– When selling a car for 1000
Scenario: When selling a car for 19000 it should equal the LameCar
– As Bert
– When selling a car for 19000
=> It should equal Fiat (45 HP)
=> It should not equal BMW (200 HP)
==> OK
Scenario: When selling a car for 30000 it should equal my DreamCar
– As Bert
– When selling a car for 30000
=> It should equal BMW (200 HP)
==> OK
Scenario: When selling a car for 30000 it should equal the DreamCar
– As Bert
– When selling a car for 30000
=> It should equal BMW (200 HP)
=> It should not equal Fiat (45 HP)
>==> OK
LINQ (also Language Integrated Queries) ist momentan in aller (NET-)Munde. Wer sich mit der Syntax vertraut machen möchte kann auf MSDN 101 LINQ-Beispiele ansehen und durcharbeiten. Besonders die Samples die anonyme Typen verwenden, erzeugen eine gewisse Vorfreude bei mir.
ReSharper ist ein Plugin der Firma JetBrains für Visual Studio, das sich speziell die Produktivitätssteigerung beim Entwickeln als Ziel gesetzt hat. Besonderes Augenmerk wird dabei auf die Refactoring-Unterstüzung gelegt, also auf das nachträgliche Umgestalten von Quellcode. JetBrains wirbt damit das “intelligenteste AddIn für Visual Studio” entwickelt zu haben – doch was kann ReSharper wirklich?Â
Bei meinem Vortrag über die Programmierung in Dynamics Nav hat mir mein Navision bei der Demo leider einen Streich gespielt und ist vollkommen unmotiviert abgeraucht. Da probiert man das Ganze zu Hause unzählige Male aus und genau in der Präsentation passiert der Unfall.
[Noch schlimmer ist es jedoch, wenn man, wie es Dirk Primbs leider passiert ist, seine eigene KeyNote verpasst. Dafür ist jedoch Dariusz Parys eingesprungen.]
Abendprogramm
Das Abendprogramm gestern bestand in einer Session, in der jeder BASTA-Teilnehmer die Möglichkeit hatte 5 Minuten auf der Bühne über ein Thema seiner Wahl referieren. Dabei konnten die Zuhörer den Redner auch abwählen und selbst das Mikrofon übernehmen. Als Anreiz konnte man neben einem BASTA-Schlüßelbändchen (Trostpreis) auch attraktive Sachpreise gewinnen. Das Highlight war jedoch als ein Oracle-Mitarbeiter (O-Ton “Orahkäl”) 5 min. lang versuchte Leute zu finden, die im nächsten Jahr auch mal einen Oracle-Vortrag auf der BASTA hören wollen. Als Preis loste er sich dann ein SQL-Server Buch. 😉 Nicht zu fassen.
Aber es kam noch besser: Im Anschluss an den Oracle-Vertreter wurde Masoud Kamali auf die Bühne gebeten, seines Zeichens Gründer und Geschäftsführer des Software & Support Verlages. Er sollte in 5min. die Gründunggeschichte und die weitere Zukunft (O-Ton: “Wir schlagen Google!”) des Verlages zu erklären. Der Software & Support Verlag ist ja auch Veranstalter der BASTA und der Hauptpreis des Abends (Kostenlose Teilnahme an der BASTA 2008) wurde nun genau von deren Chef gezogen – welch eine Ironie in 10 Minuten.
Das Ticket wird nun übrigens bei Ebay versteigert und der Erlös geht an Ärzte ohne Grenzen.
Am zweiten Abend wurde dann übrigens Poker gespielt – leider ohne persönliche Einsätze, so dass eigentlich mit jeder Hand gespielt (und verloren) wurde.
Speaker-Shirts
Die Speaker laufen auf der BASTA alle mit so tollen schwarzen Polo-Shirts rum. Wie ich jedoch erfahren habe, sollte ich meins immer schön anlassen. Das Shirt von Michael Willers  ist offenbar so begehrt, dass es gestern geklaut wurde. 😉
Interessant ist in dem Zusammenhang auch der Blog-Eintrag von Benjamin Gopp 😉
Auf der Rückfahrt gab es dann noch folgendes Highlight:
Vom 21. bis 22. Mai 2007 fand die STC 2007 im Landschaftspark Duisburg statt. Da ich bereits 2005 auf der STC in Mainz war, wollte ich auch unbedingt dieses Jahr hin. Und ich kann gleich vorweg nehmen: es hat viel Spaß gemacht – nicht zuletzt da wir diesmal eine 9er Gruppe gebildet haben.
Da die Keynote am Montag (21.5.2007) bereits um 10 gehalten werden sollte, hatten wir uns entschlossen einen Tag früher anzureisen und in der Jugendherberge Duisburg Meiderich zu übernachten. Wie sich heraus stellte war die Jugendherberge nur 300 Meter vom Tagungsgelände entfernt, so dass wir uns nach dem langen Playstation-Turnier ohne Probleme bei der STC anmelden konnten.
Durch die sogenannte “LiftOff Initiative” sollen Microsoft Partner in einem Trainingsprogramm an die Technologien rund ums Web 2.0 herangeführt werden. Schwerpunkt der Trainingsmaßnahme ist die Integration der Microsoft Webtechnologien (WPF/E, ASP.NET, AJAX), Web Services und Map Point, sowie Workflow Management.
Filed under: .NET,Blogs,Tools — Steffen Forkmann at 19:54 Uhr
Aufgrund eines Blogeintrags von Damir Tomicic und den guten Erfahrungen die ich mit Akismet gemacht habe, möchte ich an dieser Stelle mal auf ein .NET Akismet-API ausmerksam machen. Arne Brachhold hat den Zugriff auf den Webservice von Akismet als .NET-Klassenbibliothek gekapselt und bietet diese .dll frei zum Download an. Man kann diese dann zum Beispiel in ASP.NET Foren oder Blogs einbauen.
Laut der Akismet-Homepage sind übrigens 95% aller Kommentareinträge Spam – auf meinem Blog wurden bisher 16.138 Kommentare als Spam identifiziert.
Bereits im letzten Jahr war ich mit meinem Kollegen Jens Hesse auf der ICE in Lingen. Dieses Jahr findet die kostenfreie Community-Tagung am 15. September statt. Die Anmeldung zur \\ice:2007 ist ab dem 01.05.07 möglich und die Teilnehmerzahl ist auf 250 begrenzt.
Marcel Hoyer von der .NET User Group Leipzig hat einen schönen Abschlussbericht zum .NET Wintercamp in Leipzig geschrieben. Ich muss sagen mir hat mein ASP.NET-Vortrag auch viel Spaß gemacht und ich hoffe ich bekomme die Gelegenheit beim .NET-Sommercamp 2007 wieder als Sprecher fungieren zu dürfen. 🙂