Soll ich von NUnit 2.4 auf xUnit umsteigen?
Bislang verwende ich NUnit 2.4 in Verbindung mit ReSharpers integriertem Test Runner. Da xUnit ein Plugin für ReSharpers Test Runner mitbringt und Features wie Generics verwendet will ich heute mal damit “spielen” um zu sehen ob sich ein Umstieg lohnt.
Download und Installation
Das Projekt wird bei CodePlex gehostet. Download. Aktuell zum jetzigen Zeitpunkt ist v1.0.2 RC1. Der Download enthält ein ZIP Archiv das man in ein Verzeichnis seiner Wahl entpackt.
Um die diversen Test Runner zu installieren startet man anschließend xunit.installer.exe und aktiviert die Test Runner die man verwenden möchte. Ferner kann man Support für das ASP.NET MVC Framework einrichten. Das führt dazu dass Templates für xUnit Tests eingerichtet werden (habe ich nicht weiter ausprobiert).
Projekt einrichten
Ich baue meine Projekte generell so auf, dass ich im Basisverzeichnis ein Verzeichnis Vendor anlege. Dort hinein kommen alle externen Abhängigkeiten, jede in ihr eigenes Unterverzeichnis. Im Falle von xUnit kopiere ich also folgende Dateien in das Verzeichnis Vendor\xUnit:
- xunit.dll / xunit.xml
xUnit Core - xunitext.dll / xunitext.xml
Erweiterungen für z.B. datengetriebene Tests - xunitext35.dll / xunitext35.xml
Extension Methods die .NET Framework 3.5 voraussetzen
Erste Ernüchterung
Der erste Schock: gibt es kein Assert.That? Nein gibt’s nicht. Zurück zur alten Assert.AreEqual Syntax? Nein, das wäre definitiv ein K.O. Kriterium gegen xUnit. Aber der Reihe nach…
Seit NUnit 2.4 verwende ich die Assert.That Syntax:
Assert.That(kunde.KreditLimit, Is.EqualTo(400));
Vor allem die Möglichkeit alle Constraints mit einem Not zu ergänzen finde ich sehr schön:
Assert.That(kunde.EMail, Is.Not.Null);
Ich finde diese neue Syntax deutlich lesbarer als die “alte”:
Assert.AreEqual(400, kunde.KreditLimit);
Tja, die Entwickler von xUnit sehen das leider anders
Es gibt noch die Extension Methods aus der Assembly xunitext35.dll. Mal sehen ob ich damit klar komme:
kunde.Name.ShouldEqual("Lieser");
Damit könnte ich mich wohl anfreunden. Aber dadurch wird die Umstellung von existierenden NUnit Tests nicht gerade einfach. Und wir haben mehrere Tausend davon…
Exceptions
Eine riesen Verbesserung gegenüber NUnit 2.4 ist Assert.Throws. Oft ist es erforderlich einen Test zu schreiben der prüft ob eine bestimmte Exception ausgelöst wird. Der Weg von NUnit, dies mit dem Attribut ExpectedException zu lösen, hat einen ganz gravierenden Nachteil: es wird nur sichergestellt dass irgendwo in meinem Test die Exception ausgelöst wird. Das ist in vielen Fällen zu grob und kann mit der neuen Assert.Throws Syntax eleganter gelöst werden:
Assert.Throws<ArgumentNullException>(() => kunde.Name = null);
Gibt es diese Syntax auf für NUnit? Google ist dein Freund… NUnit 2.5 hat’s, ist aber noch nicht “production ready”. James Newkirk hat eine Implementierung von Assert.Throws veröffentlicht die auch mit NUnit 2.4 eingesetzt werden kann.
Fazit
xUnit wäre im Prinzip das Unit Test Framework meiner Wahl:
- ReSharper Unit Test Runner wird unterstützt
- Bewusst einfach gehalten
- Assert.Throws
Dagegen spricht die fehlende Assert.That Syntax. Ferner müsste ich den Continuous Integration Prozess umstellen. xUnit bietet Support für Cruise Control .NET, aber von alleine richtet sich das schließlich nicht ein
So werde ich erst mal bei NUnit bleiben und das oben erwähnte Assert.Throws verwenden bis NUnit 2.5 “production ready” ist.
Tags: .NET
August 2nd, 2008 at 17:26
Hi Stefan,
kennst Du schon den Post von Charlie Poole?
http://nunit.com/blogs/?p=63
Ist auch zum Thema Exceptions und NUnit 2.5. NUnit 2.5 bietet dafür anscheinend auch Erweiterungen in der Constraint API ala
Assert.That( () => MethodUnderTest(anInvalidObject ),
Throws.Exception(),
Has.Property(“ParamName”).EqualTo(“myParam”) &
Has.Property(“Message”).EqualTo(“My message”) );
Viele Grüße
Björn
August 2nd, 2008 at 17:37
Hallo Björn,
ja habe ich gelesen. Strings um Properties zu benennen sind fürchterlich, zumal man das elegant mit einem lambda nebst expression tree lösen könnte:
Assert.That(() => MethodUnderTest(anInvalidObject),(),
Throws.Exception
Has.Property(e => ParamName).EqualTo(”myParam”) &
Has.Property(e => Message).EqualTo(”My message”));
Viele Grüße,
Stefan
August 3rd, 2008 at 1:04
Hast du dir MbUnit auch schon mal angeschaut?
Bin auch gerade dabei mir die Frameworks anzuschauen und vergleiche zu machen. Werde ich mir auch gleich die verschiedenen Mock Frameworks ansehen. RhinoMock, TypeIsolator, Moq
August 3rd, 2008 at 8:13
Hallo Rainer,
das aktuelle MbUnit habe ich mir noch nicht intensiv angeschaut. Ich vermute aber dass es mir auch eher “zu groß” ist. xUnit hat für mich den Vorteil dass es ganz bewusst diverse Features _nicht_ enthält. So muss ich z.B. nicht Klassen die Tests enthalten attributieren, die Tests werden auch so gefunden.
Weißt du ob MbUnit ein Assert.Throws hat?
Zu TypeMock habe ich hier schon was geschrieben, vielleicht hilft dir das weiter.
Grüße,
Stefan
August 5th, 2008 at 16:14
Hallo Stefan,
ich hab auch mit xUnit.NET gespielt. Leider ist es nicht 100% zur 64-BIT Kompatibel. Dann die wirklich interessanten Funktionen wie XUnit.net Extensions, zum Beispiel Theory (siehe, http://blog.benhall.me.uk/2008/01/introduction-to-xunitnet-extensions.html) funktioniert bei mir die Excel funktion nicht. ODBC-Fehlermeldung. Dann finde ich sehr schade das man durch Externe Software abhängig ist. Ich nutze zwar auch Resharper, aber trotzdem.
Leider finde ich das Theory bei NUnit nicht.
Wie Testet du mehrere Werte für eine Methode?
Viele Grüße
Gregor
August 5th, 2008 at 16:27
Hallo Gregor,
mit der Excelanbindung oder gar 64-Bit habe ich mich nicht befasst, dazu kann ich also leider nichts sagen. Ich würde dazu eine Mail an die Entwickler schicken.
Mehrere Werte für eine Methode teste ich folgendermaßen (dahinter steckt quasi “Extract Method”):
[Test]
public void Bei_gueltigen_Werten_klappts() {
TestDenWert(1);
TestDenWert(2);
TestDenWert(3);
//…
}
private void TesteDenWert(int i) {
Assert.That( ….. );
}
Viele Grüße,
Stefan
August 20th, 2008 at 13:24
Entschuldingung für die Späte Antwort.
Nein, MbUnit hat in der Version 2.4 leider noch kein Assert.Throws. Auf Galio bin ich mal gespannt, mit MbUnit V3 und all den TestRunner. MbUnit V3 hat dann auch ein Assert.That.
In der Zwischenzeit kannst du aber gerne die SyntaxHelpers von NUnit für MbUnit verwenden. MbUnit rühmt sich ja damit kompatibel zu NUnit zu sein. Wie gesagt, kannst du es dann verwenden
siehe http://groups.google.com/group/MbUnitUser/browse_thread/thread/7862c04b2d868742/e472c0157923b253?lnk=gst&q=assert.that#e472c0157923b253
MbUnit hat ein paar schöne neue “Spezial” Asserts. Siehe dazu die Auflistung die Phil Haack gemacht hat.
Grüße,
Rainer
August 20th, 2008 at 23:49
@Gregor: Bei NUnit und MbUnit gibt es das RowTestAttribute. Datengetriebene Tests gibt es auch bei allen glaube ich. Was die im Einzelnen unterstützen weiß ich auch nicht, da noch nie gebraucht. Mir bisher bekannt und schon fertige Erweiterungen sind: Datenbanken, Exceltabellen, Xml, Csv.
Schau dir mal den Link von Ben Hall mal an: http://blog.benhall.me.uk/2007/04/mbunit-datafixture-data-driven-unit.html
October 2nd, 2008 at 15:24
Warum verwendet ihr bei mehreren Werten keine RowTests?