Planowanie projektu z MSpec

10

Kilka dni temu podczas oglądania Gry o Tron ogarnęła mnie tak przemożna chęć pokodowania czegoś ciekawego, czegoś nowego, liźnięcia tego o czym tylko słyszałem, że ledwo doczekałem do końca odcinka żeby usiąść do komputera. I tak narodził się Redirector.

Będzie to taki mój własny prosty “url shortener”, dzięki któremu chociaż trochę poznam WebAPI, RavenDB i AngularJS. Nie wiem czy skończę, nie wiem czy rozwinę, nie wiem czy będę używał. Wiem, że te parę godzin które na razie nad nim spędziłem były przyjemne i rozwjiające, a o to przecież chodzi.

Przez pół odcinka serialu rozważałem w głowie co właściwie chciałbym finalnie osiągnąć, żeby nie usiąść do Visuala i nie zacząć bezsensownie klepać byle czego – bo to raczej prędzej niż później ląduje w koszu. Po odcinku odpaliłem OneNote i tam wpisałem parę punktów… a następnie pomyślałem, że od dawna zamierzałem poruszyć na blogu temat MSpec i nigdy chyba tego jeszcze zrobiłem. Więc wraz z Redirectorem i niniejszy post na świat przychodzi.

Machine.Specifications (bo tak brzmi pełna nazwa biblioteki) to framework do tworzenia testów BDD-way, czy też “context specification”-way. Efekty, jakie można za jego pomocą osiągnąć, są takie same jak przy użyciu xUnit, NUnit czy MSTest, ale sposób pisania testów jest nieco inny. Swego czasu, dobre dwa lata temu, napisałem cały portal (http://benefitclub.pl/) testując wszystko właśnie MSpec i baaardzo mi owe podejście podpasowało. W sieci niestety nie znajdzie się zbyt wiele materiałów czy tutoriali o MSpec, więc być może temat niedługo rozwinę.

Dziś przedstawię tylko pierwszy krok prac nad projektem – definiowanie wymagań. “Definiowanie wymagań i framework do testów? Jak to?”. A no… tak to. Po kilku chwilach zastanowienia założenia mam takie:

  • nauczę się WebAPI udostępniając funkcjonalność przekierowań z “krótkich” URLi na “długie” URLe właśnie tą biblioteką
  • przekierowania będę zliczał do RavenDB aby móc sobie powyświetlać statystyki
  • obok stworzę “normalną” aplikację MVC, która Angularem pozwoli zarządzać zdefiniowanymi “skrótami” URLi

Na tym etapie mógłbym siąść do kodowania i zapomnieć o Bożym świecie, ale zamiast tego w kilkanaście minut zaprogramowałem sobie testy określające zakres mojej pierwszej “iteracji”, ile ona by miała nie trwać. Przewaga nad normalnym spisaniem założeń w Wordzie czy OneNote jest ogromna: w każdej chwili mogę owe założenia uruchomić i sprawdzić gdzie jestem, co zostało zrobione a co jeszcze do zrobienia pozostało.

Już sam szkielet takiej dokumentacji mówi dużo, nawet jeśli nic tak naprawdę nie sprawdza i nie zawiera żadnego wykonywalnego kodu.

Zresztą zobaczcie sami:

  Environment check, when requesting root (1 test), Inconclusive
    returns success response, Inconclusive: Not implemented

  API, when requesting existing link for the first time (3 tests), Inconclusive
    behaves like valid redirection (2 tests), 
      redirects to link target, Inconclusive: Not implemented
      returns redirect response, Inconclusive: Not implemented
    adds new visit, Inconclusive: Not implemented
  API, when requesting existing link for nth time (3 tests), Inconclusive
    behaves like valid redirection (2 tests), 
      redirects to link target, Inconclusive: Not implemented
      returns redirect response, Inconclusive: Not implemented
    adds another visit, Inconclusive: Not implemented
  API, when requesting nonexisting link (1 test), Inconclusive
    returns 404 not found, Inconclusive: Not implemented

  App, when requesting root (2 tests), Inconclusive
    displays all defined links, Inconclusive: Not implemented
    returns html, Inconclusive: Not implemented
  App, when posting new link (2 tests), Inconclusive
    adds link to database, Inconclusive: Not implemented
    redirects to links page, Inconclusive: Not implemented
  App, when posting duplicate link (2 tests), Inconclusive
    redisplays the same page, Inconclusive: Not implemented
    shows error message, Inconclusive: Not implemented

To jest wyeksportowany output z test runnera R#. A kod, który spowodował wygenerowanie mi tej listy funkcjonalności, jest banalnie prosty i wygląda tak:

[Subject("Environment check")]
public class when_requesting_root
{
    It returns_success_response;
}

[Behaviors]
public class valid_redirection
{
    It returns_redirect_response;

    It redirects_to_link_target;
}

[Subject("API")]
public class when_requesting_existing_link_for_the_first_time
{
    Behaves_like<valid_redirection> valid_redirection;

    It adds_new_visit;
}

[Subject("API")]
public class when_requesting_existing_link_for_nth_time
{
    Behaves_like<valid_redirection> valid_redirection;

    It adds_another_visit;
}

[Subject("API")]
public class when_requesting_nonexisting_link
{
    It returns_404_not_found;
}

[Subject("App")]
public class when_requesting_root
{
    It returns_html;

    It displays_all_defined_links;
}

[Subject("App")]
public class when_posting_new_link
{
    It adds_link_to_database;

    It redirects_to_links_page;
}

[Subject("App")]
public class when_posting_duplicate_link
{
    It redisplays_the_same_page;

    It shows_error_message;
}

Wymyślam scenariusz, który chciałbym zaimplementować. Potem zastanawiam się “co ma się w danej sytuacji wydarzyć”. A na koniec spisuję wykorzystując składnię MSpec.

Kolejne kroki to zaimplementowanie ciała takiego testu… i jechanie z TDD w celu osiągnięcia jego funkcjonalności.

I tyle. Nie wiem w sumie co wyniknie z tego posta, może po prostu na nim się skończy i już:). A może w jakiś sposób podrążę dalej w miarę rozwoju tego mikroskopijnego projekciku.

Używał ktoś MSpec? Jeśli tak – podoba się?

Share.

About Author

Programista, trener, prelegent, pasjonat, blogger. Autor podcasta programistycznego: DevTalk.pl. Jeden z liderów Białostockiej Grupy .NET i współorganizator konferencji Programistok. Od 2008 Microsoft MVP w kategorii .NET. Więcej informacji znajdziesz na stronie O autorze. Napisz do mnie ze strony Kontakt. Dodatkowo: Twitter, Facebook, YouTube.

10 Comments

  1. używałem ale przestałem. Czasem przestawały się testy uruchamiać w ncrunch-u i r# i trzeba było zrestartować całość. Niestety męczące było pisanie speców a potem jeszcze tdd ale odnoszę wrażenie że to bardziej przez nieumiejętne dobieranie speców niż przez samo narzędzie. Ogólnie chetnie bym coś jeszcze w tym porobił ale wielki priorytet to to u mnie nie ma ;)

  2. Arek,
    “pisanie speców a potem TDD” nie musi wcale tak wyglądać -> TDD też można robić w MSpec i właśnie tak to stosowałem w podlinkowanym projekcie. Wada jest taka że nie użyję z “nowicjuszami” unit testów, bo jak do całego tematu testowania dochodzi ogarnięcie mspecowych lambd to może być zbyt skomplikowanie… ale ogólnie bardzo mi się podobało. Z uruchamianiem nie miałem problemów, ale o ncrunch się nie wypowiem bo wtedy jeszcze tego nie było:).

  3. :) tdd z mspecami – nie dziękuję, “ołwerhed” chyba za duży :) dla mnie idealny workflow to ogólny spec w mspec i porządne testy jednostkowe do tdd a dokładniej mspec bardziej jako integracyjne a jednostkowe jak jednostkowe. Z “nowicjuszami” rzeczywiście można zabić rzucają taki zestawik :)

  4. nigdy jeszcze nie korzystałem ale wygląda ciekawie. trzymam kciuki za to żebyś znalazł czas na rozwinięcie tematu :)

  5. MSpec próbowałem, ale składnia mi nie podchodzi. SpecFlow jest dla mnie bardziej naturalny. W aktualnym projekcie używam tego do testów integracyjnych i działa to świetnie. Procent czy nie lepiej pisać scenariusze po polsku? Kiedyś miałem ambicję klikać po angielsku, ale rozbolała mnie głowa jak próbowałem przekładać na język Szekspira księgowo-zusowskie terminy.

  6. Łukasz,
    Okazało się że kolejny post z MSpec “sam się napisał”, więc pewnie będzie ciąg dalszy:)

  7. jdubrownik,
    SpecFlow widziałem, ale nie wiem czy jest to coś co chcę mieć we własnym projekcie. Nie potrzebuję większej “naturalności” – dla mnie C# jest na wystarczająco wysokim poziomie, a do szczegółowych scenariuszy w gherkinie klient i tak nie będzie zaglądał bo to dla niego zbyt szczegółowe informacje. Polecam fajny wykład na ten temat (linkuję go na blogu już trzeci raz:) http://vimeo.com/26734749 ).
    MSpec wykorzystywałem do wszelkiego rodzaju testów. Co prawda w tym samym projekcie miałem tez xunit, ale testy xunit stanowiły może 5% całości.

    Co do dylematu “PL czy EN” – nie ma jednoznacznej odpowiedzi. Jeżeli klient jest z Polski i na 100% cały zespół zawsze będzie w pełni z Polski to na pewno czasami warto jest kodować po polsku właśnie żeby uniknąć problemów wynikających z tłumaczenia ciężkich zwrotów. Moja żonka np programuje w dziedzinie “leśnej” i nie wyobrażam sobie tłumaczenia nazw drzew oraz wszystkich leśnych pojęć na angielski. Zwykły człowiek nawet po polsku nie wie co one znaczą i przerzucanie tego do EN spowodowałoby że każda osoba pracująca nad projektem większość czasu siedziałaby w słowniku:). Jednak gdy pojawia się niewielka nawet szansa na to, że projekt trafi do klienta czy programistów z zagranicy to nie ma wyjścia, musi być EN.

    Ja zawsze piszę EN bo:
    1) tak wolę
    2) nie miałem projektu w “dziwnej” dziedzinie gdzie tłumaczenie byłoby problemem

  8. SpecFlow i MSpec to jednak frameworki do nieco innych zastosowań. MSpec genialnie nadaje się do łatwego i przyjemnego BDD, które ma bardziej służyć programiście – narzuca konwencję, nadaje fajny kształt scenariuszom i jest stosunkowo prosty do wdrożenia, przy czym scenariusze ciągle można pokazać klientowi. Ostatnio klient (jednak człowiek mający podloże techniczne) sam narzucił stosowanie MSpec, bo chciał kontrolować wymagania i to jak projekt ma działać bez przedzierania się przez kod.
    SpecFlow z kolei bardziej służy klientowi niż programiście – scenariusze piszemy w języku naturalnym (Gherkin) ale najważniejsze, że można ukryć za wyrażeniami pewne schematy aby podstawiać własne dane. Wtedy klient może sam konstruować swoje scenariusze, próbawać przypadków testowych ze specyficznymi danymi wejściowymi i ogólnie iść w stronę “testing by examples”. Niestety (w moim mniemaniu) to wszystko odbywa sie kosztem programisty – kod za scenariuszami jest mniej czytelny i ogólnie framework jest trudniejszy do (poprawnego) wdrożenia.
    Z tego względu ja wciąż jestem bliższy MSpec :)

  9. Pingback: Testowanie infrastruktury WebAPI z MSpec | Maciej Aniserowicz o programowaniu

  10. Pingback: "Test reuse" w MSpec | Maciej Aniserowicz o programowaniu