Assert.Multiple

NUnit w wersji 3.6 wprowadził dość ciekawą funkcję – Assert.Multiple. Dzięki niej, dostajemy informacje na temat wszystkich testów, które nie przeszły. Przyjrzyjmy się temu bliżej…

Do tej pory, używając kilku asercji naraz, jedna niespełniona asercja powodowała, że dalszy kod nie jest wykonywany.

Continue reading

TDD: Technika, metoda, metodologia czy metodyka?

Test-Driven Development pojawia się w kontekstach:

  • techniki,
  • metody,
  • metodologii
  • i metodyki.

Które z tych określeń poprawnie definiuje TDD?

Zacznijmy od definicji poszczególnych pojęć:

technika:

«wiedza na temat praktycznego wykorzystania osiągnięć nauki w przemyśle, transporcie, medycynie itp.; też: praktyczne wykorzystanie tej wiedzy»

lub:

 «metoda»

metoda:

«świadomie stosowany sposób postępowania mający prowadzić do osiągnięcia zamierzonego celu»

metodologia:

«nauka o metodach badań naukowych stosowanych w danej dziedzinie wiedzy»

metodyka:

«zbiór zasad dotyczących sposobów wykonywania jakiejś pracy»

Werdykt: TDD to technika, metoda lub metodyka tworzenia oprogramowania. Nazywanie TDD metodologią jest błędne.

Źródło: http://sjp.pwn.pl

Kurs TDD – update źródeł

FYI—

Zaktualizowałem biblioteki dla projektu TDD Course https://github.com/dariusz-wozniak/TddCourse:

  • NUnit 2.6.4→3.5.0
  • Moq 4.2.1510.2205→4.5.23.0
  • FluentAssertions 4.1.1→4.15.0

Co za tym idzie:

  • W najnowszym NUnicie nie jest wspierany atrybut ExpectedException. Był opisany w części o testowaniu wyjątków. Zamiast atrybutu, powinno się używać Assert.Throws lub podobnych.
  • Zmieniła się idea testowania wywołań asynchronicznych, co opisywała część 13. kursu.

Wszystkie zmiany znajdują się w commicie:

https://github.com/dariusz-wozniak/TddCourse/commit/180846157f6b7506b268c14a5a51cad2059bbb0e

Podsumowanie kursu TDD

Minęło łącznie 1255 dni od pierwszej części kursu TDD opublikowanego 20 kwietnia 2013…

Był to pierwszy post na tym blogu, a sam kurs miał dyktować kierunek tego bloga na najbliższe 2-3 lata. Kończąc cykl częścią 25. nadszedł czas na mini-podsumowanie kursu…

Dlaczego napisałem ten kurs?

Problem jaki powstał przy mojej nauce TDD to przede wszystkim brak źródła informacji, który oprowadził by mnie od początku do końca po tematyce testów jednostkowych dla .NET. Owszem, było w tym czasie sporo źródeł, jednak wiedza oparta w tych źródłach była albo dostosowana pod inny język, albo nieaktualna (Rhino Mocks, MsTest), albo najzwyczajniej w świecie rozrzucona po blogach i StackOverflow. Było jest i sporo świetnych artykułów, które traktują TDD dla .NET, także w polskiej blogosferze, ale brakowało jednak poprowadzenia programisty, przysłowiowo, za rękę.

Pomyślałem, że taki kurs to świetne paliwo do bloga, zebrałem i zapisałem różne wycinki i magic – zacząłem pisać :) Moim zamiarem było stworzenie cyklu, który poprowadzi programistę przez ścieżkę nauki TDD – począwszy od napisania pierwszego testu jednostkowego, po mockowanie, aż po rozważania teoretyczne.

Sama tematyka to nic nowego w świecie programistycznym. I, jakby się mogło wydawać, nic też trudnego. W praktyce może to wyglądać jednak zupełnie inaczej. Istotną kwestią jest, prócz przygotowania merytorycznego, kultura zespołu i firmy. Jeżeli zatem brakuje czasu na setup i zrobienie porządków z unit testami, należałoby się zastanowić nad kulturą miejsca pracy. Z tego też powodu wysnułem kilka rozważań na temat kilku pułapek (code coverage), jak i podstawowego pytania – czy to się w ogóle opłaca?

Continue reading

Kurs TDD cz. 25: Otwarte pytania

To już ostatnia część kursu TDD (przed podsumowaniem) na tym blogu. Tym razem, formuła artykułu jest odmienna. Zamiast przedstawiać dane zagadnienie, to ja pytam Ciebie, czytelniku, o TDD…

Jeśli uczysz się TDD, to warto przed wygooglowaniem odpowiedzi zastanowić się nad każdym z tych punktów i postarać się odpowiedzieć na pytanie.

W przypadku, kiedy twój zespół uczy się TDD, to polecam zrobić brainstorming i do każdego pytania zebrać odpowiedzi grupy. Prowadząc kilka szkoleń na ten temat, zauważyłem że taka formuła sprawdza się idealnie jeśli te pytania na zadamy na początku i jeszcze raz, na końcu kursu, porównując odpowiedzi.

Continue reading

Kurs TDD cz. 24: Czy pisać testy jednostkowe do istniejącego kodu (legacy code)?

Najprawdopodobniej spotkałeś się z tym problemem: Kod zastany, napisany przez nas lub nie, na pewno nie perfekcyjny i ostatecznie bez testów jednostkowych (ang. legacy code). Co teraz? Wstrzymać dotychczasowe prace nad projektem i pisać testy jednostkowe? A może całkowicie zaniechać pisania testów, bo skoro nigdy nie było testów, to po co pisać je teraz?

Do tej pory omawialiśmy TDD z perspektywy pisania nowego kodu. Jak wygląda sytuacja w przypadku istniejącego już kodu? Na początek warto zastanowić się nad kilkoma pytaniami:

  • Czy powinno się poświęcać czas i zasoby, czasem wstrzymując dotychczasowe prace, na pisanie testów jednostkowych do kodu już istniejącego?
  • …Jeśli tak, to którą część aplikacji pokryć w pierwszej kolejności?
  • Jak bezpiecznie refaktoryzować kod, aby nie wprowadzić błędu do istniejącego kodu?
  • W jaki sposób powinno się pisać kody jednostkowe przy wprowadzaniu zmian do istniejącego kodu?

Continue reading

Kurs TDD cz. 23: Czy to się opłaca?

Test-Driven Development ma niezaprzeczalnie bardzo pokaźną liczbę zalet, jednak jednym z problemów stojących na przeszkodzie we wdrożeniu i stosowaniu tej techniki jest fakt, że pisanie testów jednostkowych wymaga większego nakładu czasowego programisty. Nie licząc czasu na zmianę sposobu myślenia oraz naukę zespołu, pisanie testów jednostkowych może trwać nawet dwukrotnie dłużej niż w sposób “beztestowy”.

Warto więc zadać podstawowe pytanie:

Czy TDD się opłaca? Spójrzmy na TDD okiem biznesowym…

Koszt zmian

Barry Boehm we wczesnych latach 80. ubiegłego wieku opublikował statystyki, z których wynikało że koszty zmian w oprogramowaniu oraz łataniu dziur w aplikacjach rosną w znaczący sposób z czasem życia programu. Analiza amerykańskich korporacji, m.in. Hewlett-Packard, IBM, Hughes Aircraft i TRW, wskazywała że cena zmian w oprogramowaniu rośnie wraz z przejściem do kolejnej fazy iteracyjnego modelu kaskadowego (tak, tak – waterfall):

  • Wymagania biznesowe
  • Analiza i projektowanie
  • Tworzenie kodu
  • Testowanie
  • Produkcja

Zmiana kodu po fazie analizy, tworzenia kodu, przetestowania go oraz oddaniu w ręce klienta może być nawet dwustukrotnie (!!) wyższa niż na etapie zbierania wymagań biznesowych. Oczywiście, wartość ta zależy od wielu czynników, takich jak na przykład wielkość i złożoność projektu. W pesymistycznym scenariuszu, koszt zmian rośnie wykładniczo.

Zobrazujmy taki scenariusz przykładem: Jedna strona wymagań biznesowych może przełożyć się na 5 stron diagramów, 500 linii kodu, 15 stron dokumentacji oraz kilkadziesiąt przypadków testowych. W waterfallu kaskadowane są zatem nie tylko fazy procesu, ale też problemy…

waterfall

Koszt zmian w poszczególnych fazach projektu waterfallowego (na podst. Extreme Programming Explained).

Continue reading

Kurs TDD cz. 22: Pokrycie kodu testami (Code Coverage)

Pokrycie kodu (ang. code coverage) testami to:

(liczba wyrażeń pokrytych testami) / (liczba wszystkich wyrażeń) * 100%

Innymi słowy, jest to procentowy współczynnik pokrycia kodu testami. Pokrycie kodu najczęściej mierzy się badając liczbę wyrażeń (ang. statements), choć niekiedy spotkać się można z pokryciem kodu opartym o:
– ilość linii kodu,
– ilość branchy (branch coverage),
– ilość stanów (condition coverage),
– ilość funkcji, modułów lub metod.

Kiedyś w rozmowie jeden z menadżerów chwalił się, że jego zespół utrzymał założone 90% pokrycia kodu testami jednostkowymi. Z rozmowy z członkiem innego zespołu, programista poinformował mnie, że jego zespół ma roczny cel pokrycia nowo pisanego kodu testami jednostkowymi w stopniu 85%. Jest to przykład, który zapewne zna sporo ludzi ze swojego lub bliskiego podwórka. Czy zespół posiadający stopień pokrycia kodu równym 90% jest lepszy, skuteczniejszy, bądź bardziej produktywny niż zespół z pokryciem 85%? Jakie jest minimum i optimum pokrycia kodu testami jednostkowymi? Dlaczego żaden z zespołów nie postawił sobie za cel pokrycia stuprocentowego? Przyjrzymy się bliżej problemowi…

Continue reading

Kurs TDD cz. 21: Rodzaje frameworków do tworzenia atrap

Rodzaje framerków do tworzenia atrap możemy podzielić na dwie kategorie:

  • constrained (z ang. ograniczony)
  • unconstrained (nieograniczony)

constrained

Do pierwszej kategorii zaliczamy wszystkie do tej pory poznane frameworki do tworzenia atrap – Moq, FakeItEasy, NSubstite – a także Rhino Mocks, NMock oraz EasyMock. Ich cechą charakterystyczną jest ograniczona możliwość tworzenia atrap.

Biblioteki te generują kod dziedziczący atrapy w czasie rzeczywistym, w oparciu o kod pośredni (IL). Najczęściej atrapy są tworzone w oparciu o wzorzec projektowy dynamicznego proxy, który wymaga tego aby kod umożliwiał dziedziczenie. Oznacza to, że aby stworzyć atrapę potrzebujemy interfejsu do naszej klasy lub metody wirtualnej. Jako, że kluczem do stworzenia atrapy jest dziedziczenie, nasza klasa/metoda nie może być statyczna, niepubliczna, sealed oraz musi posiadać publiczny konstruktor. Oznacza to też, że kod zawarty w konstruktorze oraz polach klasy jest wykonywany przy tworzeniu atrapy.

Czym jest dynamiczne proxy?
Dynamiczne proxy to klasa, która implementuje interfejs lub klasę w trakcie wykonywania programu (run-time).

Biblioteki te są zwykle darmowe, a obiekty proxy są zwykle tworzone przy użyciu biblioteki Castle.Windsor.

unconstrained

Frameworki o “nieograniczonych możliwościach” to Typemock Isolator, JustMock i Microsoft Fakes. Są one napisane w oparciu o Common Language Runtime (CLR) Profiler, który udostępnia API pozwalające na większą kontrolę nad wykonywanym kodem. Możemy zatem wstrzykiwać nasz kod przed kompilacją kodu pośredniego oraz mamy dostęp do eventów wywoływanych w trakcie wykonywania naszego kodu.

Większa kontrola nad generowanym kodem oznacza, że frameworki te pozwalają na tworzenie atrap dla kodu, który nie musi być dziedziczony, a więc klasy/metody statyczne, prywatne, biblioteki zewnętrzne, klasy systemowe (np. DateTime), itp.

Ze względu na stopień skomplikowania pisania kodu w oparciu o API Profilera, frameworki te (poza Microsoftowym) są dostępne odpłatnie.

Continue reading

Kurs TDD cz. 20: Mockowanie DateTime.Now, random, static, itp.

Jedną z największych trudności dla osoby zaczynającej przygodę z testami jednostkowymi są:

  • Metody i klasy statyczne.
  • Niederministyczne lub/i niepowtarzalne zależności.
    • Testy jednostkowe muszą być deterministyczne i powtarzalne.
    • Musimy przyjąć zatem strategię wstrzykiwania alternatywnej implementacji dla wywołań DateTime.Now, funkcji losującej, itp.

W tym artykule przedstawię jedną ze strategii tworzenia atrap dla tego typu zależności.

Continue reading