xUnit – nowy lepszy framework dla Unit Testów

Po co mi jakiś inny framework do testowania? Wszystko co mam, wystarcza mi – ktoś może powiedzieć. Gdybym miał kogoś przekonać do xUnit to odpowiednim powiedzeniem byłoby

Lepsze jest wrogiem dobrego.

NUnit ma wady

NUnit rozpoczął żywot ponad 10 lat temu (wczesne 2002). .NET wygladał wtedy inaczej. Jeśli wtedy wybrano złe rozwiazania to ten projekt musi utrzymywać kompatybilność wsteczną dla tych wszystkich rzeczy, które nie są najlepsze. (ok – xUnit nie jest jakąś super świeżynką – wystartował ok. 2008 roku.)

Dotychczas korzystałem z NUnit, ale już się przesiadłem.

Izolacja testów

Jedna ze zmian to sprawa izolacji testów. Mamy wiele testów w klasie, mamy też prywatne pola, serwisy, z których korzystają testy (można powiedzieć, że to antypattern, ale mnie osobiście szlag trafia, gdy w każdym teście powtarzam tę samą logikę odpowiedzialną za Arrange, więc jednak Code Reuse). W NUnit aby zapewnić izolację korzystamy ze specjalnych metod (atrybuty [SetUp] i [TearDown]).

Problem z tym jest taki, że trzeba explicite napisać metodę z atrybutem [SetUp]. Podejście to od dłuższego czasu było krytykowane. Jedną z podstawowych rzeczy jakie wiem o Unit Testach jest to, że powinny uruchamiać się w izolacji (może to znaczyć różne rzeczy). W xUnit jest to bardziej naturalne, po prostu to co w konstruktorze będzie naszym SetUp’em, do każdego testu zostanie utworzona nowa klasa.

Jeśli chcemy, aby wiele testów operowało na tych samych danych (kosztownych w tworzeniu), to oczywiście da się to prosto zrobić – IUseFixture<T>.

Bardziej szczegółowe oczekiwanie wyjątków

Atrybut [ExpectedException] z NUnit został zastąpiony przez Assert.Throws<T>:

Assert.Throws<InvalidOperationException>(() => operation());

Pozwala to zawęzić oczekiwanie wyjątku tylko do określonej linijki. Przy atrybucie wyjątek mógł polecieć z dowolnego miejsca testu.

Celowe ograniczenia

Dyskusja na jaką natrafiłem, gdy wyszło na jaw, że xUnitowa metoda Equal() nie posiada przeładowań umożliwiających podanie opisu przyczyny niepowodzenia testu.

Then how do we provide more info upon a failed assert ? Let’s say I am testing a parser and want to specify what was the buffer size and the line/position in the file where the assert failed.

– The simple answer is: you don’t. If you need messages because you can’t understand the test code otherwise, then that’s the problem (and not the lack of a message parameter).

Jak najbardziej da się pisać testy, tak jak koleś odpowiedział. Nazywa się to BDD lub inne buzzwords 😉 i jest poza scopem dzisiejszego wpisu.

Pogrzebałem w projektach i jedyne przykłady jakie znalazłem to podawanie opisowych assertów, które można spokojnie pominać.

[Test]
public void GIVEN_EpiserverRecipeRepository_WHEN_GetRecipesIsCalled_AND_ListOfMenyRecipePagesIsPassed_THEN_RecipeListIsReturned()
{
    // (...) Arrange
    // (...) Act

    Assert.IsNotNull(recipes, "Null returned for invalid page reference");
    Assert.AreEqual(4, recipes.Count(), "Invalid number of recipes returned");
}

Syntactic sugar

Nie trzeba tagować klasy testowej żadnym atrybutem. Testy mogą być również metodami stytycznymi. To jednak tylko szczegóły.

Rzeczy na start

Resharper 8.2 dla Visual Studio 2013 potrzebuje doinstalować „xUnint.net Test Support” poprzez R# Extensions Manager. Następnie restart VS.
Kombinacja [Test]/[TestCase] z NUnit odpowiada [Theory]/[InlineData](i kilka innych, xUnit jest bardziej data driven). Musimy doinstalować nugetem inną bibliotekę xUnit.Extensions, żeby z nich korzystać.

Źródła:
WhyDidWeBuildXunit (Lessons learned)

Advertisements
Ten wpis został opublikowany w kategorii Programowanie i oznaczony tagami , , , . Dodaj zakładkę do bezpośredniego odnośnika.

Jedna odpowiedź na „xUnit – nowy lepszy framework dla Unit Testów

  1. Michal Franc pisze:

    To warto jeszcze nadmienic o ksiazce
    X Unit Test Patterns – http://xunitpatterns.com/

    Wg mnie a must have to read. Ksiazka ktora przedstawa podstawowa terminologie zwiazana z testami jednostkowymi oraz TDD.

Możliwość komentowania jest wyłączona.