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).

xUnitInstaller

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.

Technorati-Tags: ,
Kick it on dotnet-kicks.de

Tags:

9 Responses to “Soll ich von NUnit 2.4 auf xUnit umsteigen?”

  1. Björn Rochel Says:

    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

  2. Stefan Lieser Says:

    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

  3. Rainer Schuster Says:

    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

  4. Stefan Lieser Says:

    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

  5. bfreakout Says:

    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

  6. Stefan Lieser Says:

    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

  7. Rainer Schuster Says:

    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

  8. Rainer Schuster Says:

    @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

  9. Mariusz Says:

    Warum verwendet ihr bei mehreren Werten keine RowTests?