Wprowadzenie
Jako konsultant współpracowałem z wieloma zespołami i organizacjami. Miałem okazję spotykać zespoły korzystające z programowania sterowanego testami (ang. test-driven development, TDD) oraz zespoły, które przeprowadzały testy jednostkowe bez stosowania podejścia w stylu TDD. Zetknąłem się również z zespołami, których członkowie sądzili, że wykonują testy jednostkowe, podczas gdy tak naprawdę przeprowadzano testy integracyjne. Miałem również styczność z zespołami, w których nie wykonywano żadnych testów. Na podstawie zebranych danych empirycznych zacząłem nabierać przekonania, że największy sukces odnosiły zespoły przyjmujące podejście w stylu TDD, przy czym nie działo się tak z powodu zastosowania programowania sterowanego testami. Podejście w stylu TDD jest skutkiem pasji.
Programowanie sterowane testami oznacza testy jednostkowe plus pasję. W niektórych zespołach testy jednostkowe są narzucone, więc programiści nie mają wyjścia. Jednak podejście w stylu TDD rzadko jest narzucane i decyzja o jego zastosowaniu należy do programistów. Nie trzeba dodawać, że programiści pracujący z pasją tworzą wysokiej jakości projekty, które z kolei mają większą szansę na osiągnięcie sukcesu.
Programowanie sterowane testami jest zwykle łączone z wybranymi bądź wszystkimi aspektami architektury DDD (ang. domain-driven design). Dlatego też w książce omówiłem podejścia w stylu TDD i DDD, aby przedstawić znacznie bardziej rzeczywiste przykłady. Ponadto chciałem odzwierciedlić obecny stan rynku, który jest podzielony między dwiema kategoriami baz danych: relacyjnymi i opartymi na dokumentach. Dlatego też pozwoliłem sobie dodać przykładowe rozdziały dotyczące każdej z tych kategorii, aby dzięki temu pokazać różnice w implementacji testów jednostkowych, a jednocześnie zachować pragmatyczny charakter książki.
Nie daj się zwieść objętości książki; to diagramy i przykładowe fragmenty kodu sprawiły, że jest tak duża. Starałem się unikać przestarzałych i niepraktycznych teorii, aby w ten sposób zmniejszyć ilość omawianego materiału i skoncentrować się na najważniejszych kwestiach.
Podejście i testy jednostkowe są wymieniane w większości obecnych ofert pracy, stanowią wymaganie podczas wykonywania przykładowych projektów w trakcie rekrutacji, a także pojawiają się w pytaniach zadawanych kandydatom na stanowiska związane z programowaniem. Jeżeli chcesz dowiedzieć się więcej na te tematy i stać się programistą stosującym podejście w stylu TDD, masz w ręku odpowiednią książkę.
Dostępnych jest wiele innych dobrych książek poświęconych programowaniu sterowanemu testami i przeznaczonych dla programistów .NET, więc być może zastanawiasz się, dlaczego akurat masz sięgnąć po tę pozycję. W swojej książce zamierzam pokazać Ci rzeczywiste implementacje przez wejście do świata architektury DDD, relacyjnych baz danych oraz baz danych opartych na dokumentach. Zaprezentuję drzewo decyzyjne modelu mentalnego, którego używają zespoły stosujące programowanie sterowane testami. Pokażę również związek między regułami SOLID a podejściem w stylu TDD, a także omówię niezapomniane najlepsze praktyki, znane jako wskazówki FIRSTHAND, dotyczące podejścia w stylu TDD.
Moim celem było napisanie książki, która pozwoli Ci stać się pewnym siebie praktykiem programowania sterowanego testami, a przynajmniej praktykiem testów jednostkowych. Mam nadzieję, że osiągnąłem ten cel.
Dla kogo przeznaczona jest ta książka?
Programowanie sterowane testami to ważne podejście stosowane podczas opracowywania, dokumentowania i testowania aplikacji od samego początku jej powstawania. Gdy programista chce otrzymać wyższe stanowisko, ze słowem senior w nazwie, wówczas musi znać zagadnienia związane z programowaniem sterowanym testami, testami jednostkowymi, dublerami używanymi w trakcie testów (ang. test doubles), mechanizmem wstrzykiwania zależności itd.
To jest książka przeznaczona dla programistów .NET średniego i wyższego szczebla, którzy szukają możliwości wykorzystania potencjału drzemiącego w programowaniu sterowanym testami, aby tworzyć wysokiej jakości aplikacje. Przyjąłem założenie, że masz podstawową wiedzę z zakresu programowania w języku C# oraz programowania zorientowanego obiektowo. Nie musisz nic wiedzieć na temat koncepcji TDD ani testów jednostkowych. W książce znajdziesz dokładne omówienia wszystkich koncepcji programowania sterowanego testami i testów jednostkowych, a ponadto stanowi ona doskonały przewodnik dla programistów, którzy chcą zupełnie od podstaw tworzyć aplikacje z zastosowaniem podejścia w stylu TDD, oraz tych, którzy dopiero planują wykorzystanie testów jednostkowych w swoich organizacjach.
Co znajdziesz w książce?
Niniejsza książka przedstawia programowanie sterowane testami i jego ekosystem na platformie .NET, obejmujący zintegrowane środowiska programistyczne oraz biblioteki, a także wyjaśnia proces przygotowania odpowiedniego środowiska. Na początku zostaną omówione zagadnienia pozwalające na zdobycie podstawowej wiedzy z zakresu programowania sterowanego testami, obejmujące m.in. wstrzykiwanie zależności, testy jednostkowe i dublery używane podczas testów. Następnie, po przedstawieniu podejścia w stylu TDD oraz związanych z nim najlepszych praktyk, pokażę budowanie aplikacji zupełnie od początku, z wykorzystaniem architektury DDD.
W książce znajdziesz również podstawowe informacje związane z przygotowaniem potoku ciągłej integracji i obsługą starszego kodu, stworzonego bez uwzględnienia zadań związanych z jego przetestowaniem. Na koniec przedstawię informacje o sposobach zastosowania podejścia w stylu TDD we własnej organizacji.
Rozdział 1., "Przygotowanie pierwszej implementacji TDD", nie zawiera przydługiego wprowadzenia ani teorii, a zamiast tego od razu przechodzi do kwestii związanych z wyborem zintegrowanego środowiska programistycznego i przygotowania pierwszej implementacji w stylu TDD, aby Czytelnik otrzymał przedsmak tego, co znajduje się w książce.
Rozdział 2., "Wprowadzenie do mechanizmu wstrzykiwania zależności", przedstawia zaawansowane reguły programowania zorientowanego obiektowo, które trzeba poznać, aby zrozumieć koncepcję mechanizmu wstrzykiwania zależności. Znajdziesz tutaj również wiele przykładów.
Rozdział 3., "Rozpoczęcie pracy z testami jednostkowymi", zawiera krótkie wprowadzenie do frameworka xUnit oraz podstawy związane z testami jednostkowymi.
Rozdział 4., "Rzeczywiste stosowanie testów jednostkowych z wykorzystaniem dublerów używanych podczas testów", zawiera omówienie wielu zagadnień związanych z namiastkami, imitacjami i biblioteką NSubstitute oraz przedstawia wiele innych kategorii testów.
Rozdział 5., "Programowanie sterowane testami", pokazuje, jak tworzyć testy jednostkowe, ale z wykorzystaniem podejścia w stylu TDD, a także przedstawia ich wady i zalety.
Rozdział 6., "Wskazówki FIRSTHAND dotyczące programowania sterowanego testami", zawiera dokładne omówienie najlepszych praktyk związanych z testami jednostkowymi i programowaniem sterowanym testami.
Rozdział 7., "Pragmatyczne omówienie architektury DDD", przedstawia wprowadzenie do zagadnień dotyczących architektury DDD, usług i repozytoriów.
Rozdział 8., "Opracowanie aplikacji pozwalającej na rezerwowanie wizyt", prezentuje specyfikację naszej przykładowej aplikacji, którą zbudujemy w dalszej części książki z wykorzystaniem architektury DDD i programowania sterowanego testami.
Rozdział 9., "Wykorzystanie Entity Framework i relacyjnej bazy danych do opracowania aplikacji pozwalającej na rezerwowanie wizyt", pokazuje przykład budowania aplikacji z zastosowaniem programowania sterowanego testami i relacyjnej bazy danych.
Rozdział 10., "Wykorzystanie wzorca repozytorium i opartej na dokumentach bazy danych do opracowania aplikacji pozwalającej na rezerwowanie wizyt", pokazuje przykład budowania aplikacji z zastosowaniem programowania sterowanego testami, bazy danych opartej na dokumentach oraz wzorca repozytorium.
Rozdział 11., "Wdrożenie potoku ciągłej integracji za pomocą usługi GitHub Actions", wyjaśnia, jak używać usługi GitHub Actions do utworzenia potoku ciągłej integracji przeznaczonego dla aplikacji zbudowanej w rozdziale 10.
Rozdział 12., "Praca z uaktualnionymi projektami", pokazuje przebieg procesu, gdy rozważane jest użycie programowania sterowanego testami i testów jednostkowych w starszych projektach.
Rozdział 13. "Zawiłości związane ze stosowaniem programowania sterowanego testami", wyjaśnia przebieg szkolenia, gdy organizacja ma wdrożyć programowanie sterowane testami.
Dodatek A., "Biblioteki, których najczęściej używa się podczas stosowania testów jednostkowych", przedstawia wybrane przykłady związane z bibliotekami MSTest, NUnit, Moq, Fluent Assertions i AutoFixture.
Dodatek B., "Zaawansowane scenariusze związane z używaniem imitacji", prezentuje nieco bardziej zaawansowany scenariusz z użyciem biblioteki NSubstitute.
Jak najwięcej wynieść z lektury tej książki?
W książce przyjąłem założenie, że znasz składnię języka programowania C# oraz masz przynajmniej roczne doświadczenie w pracy z Visual Studio bądź podobnym zintegrowanym środowiskiem programistycznym. Wprawdzie omówię reguły programowania zorientowanego obiektowo, ale mimo to założyłem, że znasz już jego podstawy.
Oprogramowanie użyte w książce
Wymagania co do systemu operacyjnego
Visual Studio 2022
Windows lub macOS
Fine Code Coverage
Windows
SQL Server
Windows, macOS (Docker) lub Linux
Cosmos DB
Windows, macOS (Docker) lub Linux (Docker)
Biblioteki i frameworki
Wymagania co do systemu operacyjnego
.NET Core 6, C# 10
Windows, macOS lub Linux
xUnit
Windows, macOS lub Linux
NSubstitute
Windows, macOS lub Linux
Entity Framework
Windows, macOS lub Linux
Aby maksymalnie wykorzystać materiał zamieszczony w książce, musisz mieć zintegrowane środowisko programistyczne przeznaczone do tworzenia kodu źródłowego w języku C#. Zdecydowałem się na użycie Visual Studio 2022 Community Edition, a alternatywne opcje przedstawię na początku rozdziału 1.
Jeżeli masz tę książkę w wersji elektronicznej (e-book), wówczas gorąco zachęcam Cię do samodzielnego wypisywania kodu bądź też pobrania go z repozytorium GitHub (jego adres podam w następnym podrozdziale). Dzięki temu możesz uniknąć wielu potencjalnych błędów związanych z kopiowaniem i wklejaniem kodu źródłowego.
Pobieranie przykładów kodu
Wszystkie pliki z kodem źródłowym opisanym w tej książce są dostępne w repozytorium GitHub pod adresem https://github.com/PacktPublishing/Pragmatic-Test-Driven-Development-in-C-Sharp-and-.NET. Wszelkie uaktualnienia omówionego kodu będą udostępniane poprzez wymienione repozytorium.
Przyjęte konwencje
W książce zastosowałem wiele różnych stylów tekstu, pozwalających na rozróżnienie poszczególnych rodzajów informacji.
KodWTekście. Ten styl wskazuje na fragmenty kodu w tekście, nazwy tabel baz danych i dane wejściowe wprowadzone przez użytkownika. Oto przykład: "Wykonanie tego fragmentu kodu zakończy się niepowodzeniem, ponieważ użycie UnitTest2 przed UnitTest1 prowadzi do niezaliczenia testu".
Kursywa. Tym stylem oznaczyłem nazwy plików i katalogów, rozszerzenia plików, ścieżki dostępu, adresy URL, a także adresy w serwisie Twitter. Oto przykład: "Otwórz plik Class1.cs w katalogu MyProject".
Blok kodu przedstawia się następująco:
public class SampleTests
{
private static int _staticField = 0;
[Fact]
public void UnitTest1()
{
_staticField += 1;
Assert.Equal(1, _staticField);
}
[Fact]
public void UnitTest2()
{
_staticField += 5;
Assert.Equal(6, _staticField);
}
}
Gdy będę chciał zwrócić Ci uwagę na konkretny fragment kodu, wówczas skorzystam z pogrubienia elementów bądź całych wierszy:
public class SampleTests
{
private static int _staticField = 0;
[Fact]
public void UnitTest1()
{
_staticField += 1;
Assert.Equal(1, _staticField);
}
[Fact]
public void UnitTest2()
{
_staticField += 5;
Assert.Equal(6, _staticField);
}
}
Polecenia wydawane w wierszu poleceń zostaną zapisane w pokazany tutaj sposób.
GET https://webapidomain/services
Nowe pojęcia i ważne słowa są zapisywane pogrubioną czcionką. Słowa widoczne na ekranie, w menu lub w oknach dialogowych są przedstawiane w tekście następująco: "Po zainstalowaniu lokalnego emulatora, musisz pobrać ciąg tekstowy połączenia. W tym celu przejdź pod adres https://localhost:8081/_explorer/index.html i skopiuj zawartość pola Primary Connection String".
Wskazówki lub ważne uwagi
Wskazówki lub ważne uwagi będą się pojawiać w takich ramkach.
Rozdział 1. Przygotowanie pierwszej implementacji TDD
Zawsze uwielbiałem książki, które rozpoczynały się od krótkiego przykładu przedstawiającego zagadnienia omawiane w tekście, a dopiero później zawierały dokładne omówienie tematu. Dzięki temu wiem, co będę poznawał podczas lektury książki. Chciałbym zastosować takie samo podejście i na początku książki zamieścić przykład w postaci niewielkiej aplikacji.
W tym miejscu zasymuluję minimalne wymagania biznesowe, a podczas ich implementacji przedstawię wybrane koncepcje związane z testami jednostkowymi i programowaniem sterowanym testami (ang. test-driven development , TDD ). Nie przejmuj się, jeśli te koncepcje nie są dla Ciebie jasne bądź wymagają dalszych wyjaśnień, ponieważ w tym rozdziale celowo przedstawiam je tylko pokrótce, aby dać Ci przedsmak tego, co znajdziesz w książce. W pozostałej części tekstu znajdziesz dokładne omówienie wszystkich poruszonych tutaj koncepcji.
Muszę dodać, że w książce wymiennie używam pojęć testów jednostkowych i podejścia w stylu TDD , z niewielką różnicą między nimi. Wszystko stanie się jaśniejsze w rozdziale 5.
Natomiast w tym rozdziale poruszam następujące tematy:
wybór
zintegrowanego środowiska programistycznego (ang.
integrated development environment , IDE), utworzenie szkieletu rozwiązania razem z testami jednostkowymi, implementacja wymagań z zastosowaniem programowania sterowanego testami.
Zanim zakończysz lekturę rozdziału, będziesz umiał dość komfortowo tworzyć proste testy jednostkowe za pomocą xUnit oraz ogólnie poznasz podejście w stylu TDD.
Wymagania techniczne
Kod dla tego rozdziału znajdziesz w repozytorium GitHub pod adresem https://github.com/PacktPublishing/Pragmatic-Test-Driven-Development-in-C-Sharp-and-.NET/tree/main/ch01 .
Wybór zintegrowanego środowiska programistycznego
Z perspektywy podejścia w stylu TDD wybór zintegrowanego środowiska programistycznego będzie miał wpływ na Twoją produktywność. Implementacja podejścia wykorzystującego programowanie sterowane testami może być wspomagana przez IDE oferujące możliwości refaktoryzacji i generowania kodu źródłowego. Wybór odpowiedniego środowiska IDE zmniejszy liczbę powtarzających się - i potencjalnie nużących - zadań koniecznych do wykonania.
W kolejnych punktach przedstawię trzy popularne środowiska IDE, które oferują obsługę projektów w języku C#: Visual Studio ( VS ), Visual Studio Code ( VS Code ) i JetBrains Rider .
Microsoft Visual Studio
W tym rozdziale oraz w pozostałej części książki będę używał Visual Studio 2022 Community Edition - możesz skorzystać również z wydań Professional i Enterprise . Programiści indywidualni mogą bezpłatnie używać wydania Visual Studio Community Edition do tworzenia własnych aplikacji, zarówno bezpłatnych, jak i komercyjnych. Z kolei w przypadku organizacji istnieją pewne ograniczenia. Z pełną treścią licencji oraz ze szczegółami produktu możesz się zapoznać na stronie https://visualstudio.microsoft.com/vs/ community/ .
Jeżeli masz wcześniejsze wydanie Visual Studio i nie chcesz go uaktualniać, wówczas używane w książce VS 2022 Community Edition możesz zainstalować równolegle z dowolną poprzednią wersją.
Wersje Visual Studio 2022 przeznaczone dla platform Windows i Mac zawierają narzędzia wymagane do utworzenia kodu oraz uruchomienia testów. W tej książce wszystkie projekty, rysunki i procedury zostały wykonane z użyciem wydania VS przeznaczonego dla platformy Windows . Możesz je pobrać ze strony https://visualstudio.microsoft.com/downloads/ .
Aby można było wykonywać projekty zamieszczone w książce, podczas instalowania VS trzeba zaznaczyć pole wyboru przynajmniej przy ASP.NET and web development , jak pokazałem na rysunku 1.1.
Rysunek 1.1. Wybór komponentów w trakcie instalacji Visual Studio
Jeżeli w systemie masz już zainstalowane wcześniejsze wydanie Visual Studio, wówczas możesz sprawdzić, czy komponent ASP.NET and web development jest dostępny. W tym celu wykonaj wymienione tutaj kroki.
W Windows przejdź do
Ustawienia/Aplikacje/Zainstalowane aplikacje . Odszukaj
Visual Studio na wyświetlonej liście aplikacji. Kliknij przycisk przedstawiający pionowy wielokropek (trzy kropki jedna pod drugą). Wybierz opcję
Modyfikuj , jak pokazałem na rysunku 1.2.
Rysunek 1.2. Modyfikacja ustawień opcji instalacyjnych Visual Studio
Visual Studio to duże oprogramowanie, składające się z wielu komponentów do zainstalowania. Ponadto już po zainstalowaniu to środowisko IDE będzie uruchamiało się wolniej od produktów Visual Studio Code bądź Rider , które również są przedstawione w rozdziale.
ReSharper
JetBrains ReSharper to popularna komercyjna wtyczka przeznaczona dla Visual Studio, która wzbogaca je o wiele dodatkowych funkcjonalności. Z perspektywy programowania sterowanego testami jesteśmy zainteresowani wymienionymi tutaj aspektami:
Refaktoryzacja . Wtyczka ReSharper zapewnia wiele związanych z refaktoryzacją funkcji, które okazują się przydatne na etapie refaktoryzacji kodu źródłowego.
Generowanie kodu . Ta funkcja okazuje się szczególnie przydatna, gdy najpierw tworzy się testy jednostkowe, a dopiero później generuje kod źródłowy.
Testy jednostkowe . Wtyczka ReSharper wspomaga istniejące w Visual Studio narzędzia przeznaczone do pracy z testami jednostkowymi oraz zapewnia możliwość współpracy z większą liczbą frameworków testów jednostkowych.
ReSharper to produkt oferowany na zasadzie subskrypcji; dostępna jest jego 30-dniowa wersja próbna. Zachęcam do rozpoczęcia pracy z narzędziami testów jednostkowych w Visual Studio bez użycia wtyczki ReSharper. Gdy poznasz już możliwości VS w tym zakresie, wtedy sięgnij po wtyczkę ReSharper, a dostrzeżesz korzyści, jakie zapewnia.
Każde nowe wydanie Visual Studio zawiera dodatkowe możliwości w zakresie refaktoryzacji i generowania kodu, podobne do oferowanych przez wtyczkę ReSharper. Jednak obecnie to ReSharper ma więcej funkcji zaawansowanych.
O wtyczce ReSharper wspominam tylko w tym miejscu książki. Więcej informacji na jej temat znajdziesz na stronie https://www.jetbrains.com/resharper/ .
JetBrains Rider
JetBrains to firma stojąca za środowiskiem IDE Rider oraz popularną wtyczką do Visual Studio, czyli ReSharper . Jeżeli zdecydujesz się na wybór JetBrains Rider jako środowiska programowania na platformie .NET, wówczas będziesz mieć dostęp do wszystkich funkcjonalności, które są wymagane podczas lektury niniejszej książki. Rider oferuje wiele funkcji, m.in.:
potężne środowisko
wykonywania testów jednostkowych , które może konkurować z oknem
Test Explorer w Visual Studio, rozbudowane możliwości w zakresie refaktoryzacji i generowania kodu źródłowego, wraz ze znacznie bardziej zaawansowanymi funkcjami niż te dostępne w Visual Studio 2022.
Wymienione punkty mają znaczenie krytyczne podczas budowania systemu z wykorzystaniem podejścia w stylu TDD . Mimo to w książce zdecydowałem się na użycie środowiska Visual Studio zamiast Rider. Niemniej jednak zamieszczone w tekście informacje można zastosować również w przypadku środowiska Rider. Trzeba tylko pamiętać, że Rider korzysta z innego systemu menu i innych skrótów klawiszowych.
Uwaga
VS .NET (wydanie Visual Studio zapewniające obsługę platformy .NET) pojawiło się w lutym 2002 roku, podczas gdy środowisko Rider dopiero w sierpniu 2017 roku. Dlatego też produkt firmy Microsoft jest znacznie częściej używany przez programistów .NET. To miało wpływ na wybór środowiska IDE na potrzeby niniejszej książki.
Więcej informacji na temat środowiska Rider znajdziesz na stronie https://www.jetbrains.com/rider/ .
Visual Studio Code
Jeżeli zaliczasz się do zwolenników Visual Studio Code, z zadowoleniem przyjmiesz informację o dodaniu przez Microsoft wizualnej obsługi testów jednostkowych (co ma krytyczne znaczenie w programowaniu sterowanym testami) do wersji Visual Studio Code 1.59, wydanej w lipcu 2021 roku.
VS Code to lekkie środowisko IDE, które zapewnia natywne opcje dotyczące refaktoryzacji oraz obsługuje wiele wtyczek refaktoryzacji opracowanych przez podmioty zewnętrzne. Prostota i elegancja VS Code mogą przyciągać wielu zwolenników programowania sterowanego testami. Jednak dostępna funkcjonalność związana z programowaniem w języku C# - zwłaszcza dla osób z doświadczeniem w stosowaniu podejścia w stylu TDD - nie jest tak zaawansowana jak ta, którą można znaleźć w produktach Visual Studio i Rider.
Wprawdzie w książce korzystam ze środowiska Visual Studio, ale przykłady można dostosować także do Visual Studio Code. Więcej informacji na temat tego produktu znajdziesz na stronie https://visualstudio.microsoft.com/downloads/ .
Wersje .NET i C#
Wydanie Visual Studio 2022 jest dostarczane razem z obsługą .NET 6 i C# 10 . Tego wydania będę używał na potrzeby niniejszego rozdziału oraz pozostałej części książki.
W swojej grupie w serwisie LinkedIn przeprowadziłem małą ankietę mającą na celu zebranie od użytkowników informacji o używanych przez nich środowiskach IDE. Wyniki tej ankiety pokazałem na rysunku 1.3.
Rysunek 1.3. Wyniki ankiety przeprowadzonej przeze mnie w serwisie LinkedIn
Jak możesz zobaczyć, najwięcej respondentów (58%) używa Visual Studio, przy czym 18% korzysta także z wtyczki ReSharper. Na drugim miejscu znalazł się Rider, który wybrało 24% badanych. Najmniejszą popularnością cieszy się Visual Studio Code (18%). Biorąc pod uwagę fakt, że w ankiecie wzięło udział jedynie 45 respondentów, wyniki są jedynie orientacyjne i na pewno nie odzwierciedlają sytuacji na rynku.
Wybór odpowiedniego środowiska IDE to indywidualna decyzja programisty. Gdy pytam programistę stosującego podejście w stylu TDD o wybrane przez niego środowisko, za każdym razem jestem przekonywany, jak świetne jest używane przez niego środowisko. Reasumując, zdecyduj się na środowisko IDE, które zapewni Ci najlepszą produktywność.
Utworzenie szkieletu rozwiązania razem z testami jednostkowymi
Skoro omówienie wymagań technicznych mamy już za sobą, możemy przejść do zbudowania naszej pierwszej implementacji. Na potrzeby tego rozdziału oraz by skoncentrować się na koncepcjach programowania sterowanego testami, rozpoczniemy od prostych wymagań biznesowych.
Przyjmujemy założenie, że jesteś programistą pracującym dla fikcyjnej firmy Unicorn Quality Solutions Inc. ( UQS ), która zajmuje się tworzeniem wysokiej jakości oprogramowania.
Wymagania
Zespoły tworzące oprogramowanie w firmie UQS stosują w trakcie tego procesu podejście zwinne (ang. agile ), więc wymagania biznesowe zostają przedstawione w postaci tzw. historyjek użytkownika .
Pracujesz nad biblioteką matematyczną, która będzie miała postać pakietu używanego przez innych programistów. Można założyć, że zajmujesz się opracowaniem funkcjonalności w bibliotece NuGet przeznaczonej do użycia przez inne aplikacje. Oto historyjka użytkownika, którą wybrałeś do zaimplementowania.
Tytuł historyjki:
Dzielenie całkowite
Opis historyjki:
Jako klient biblioteki matematycznej chcę mieć możliwość dzielenia dwóch liczb całkowitych.
Kryteria akceptacji:
Obsługa danych wejściowych typu Int32 i danych wyjściowych typu decimal.
Zapewnienie wysokiej dokładności danych wyjściowych bez ich zaokrąglania bądź jedynie z minimalnym zaokrągleniem.
Obsługa dzielenia liczb całkowitych zarówno podzielnych, jak i niepodzielnych.
Zgłoszenie wyjątku DivideByZeroException w przypadku dzielenia przez zero.
Utworzenie szkieletu projektu
Dla tej historyjki użytkownika będą potrzebne dwa projekty C#. Pierwszy to biblioteka klas zawierająca produkcyjny kod źródłowy, a drugi to testy jednostkowe dla tej biblioteki.
Biblioteka klas pozwala na umieszczanie funkcjonalności w module, który następnie może być używany przez wiele aplikacji. Podczas kompilacji powstaje plik tzw. biblioteki dołączanej dynamicznie (ang. dynamic-link library , DLL). Biblioteka klas nie może funkcjonować samodzielnie, natomiast może działać jako część aplikacji.
Jeżeli nie masz doświadczenia w pracy z biblioteką klas, na potrzeby tej książki możesz ją traktować jako aplikację działającą w konsoli (wiersz poleceń) bądź jako aplikację internetową.
Utworzenie projektu biblioteki klas
Te same projekty zostaną utworzone na dwa sposoby - za pomocą graficznego interfejsu użytkownika (ang. graphical user interface , GUI ) oraz za pomocą interfejsu wiersza poleceń (ang. command-line interface , CLI ). Wybierz preferowany przez siebie sposób bądź ten, w pracy z którym masz doświadczenie.
Użycie graficznego interfejsu użytkownika
Aby utworzyć bibliotekę klas, uruchom Visual Studio i wykonaj przedstawioną tutaj procedurę.
Wybierz opcję menu
File/New/Project . W wyświetlonym oknie dialogowym wyszukaj element
Class Library (C#) . Zaznacz znaleziony element, a następnie kliknij przycisk
Next . Na ekranie zostanie wyświetlone okno dialogowe
Add a new project , jak pokazałem na rysunku 1.4.
Rysunek 1.4. Wyszukiwanie szablonu projektu Class Library (C#)
Upewnij się, że w oknie widzisz tag C # oraz że NIE został wybrany element Class Library (.NET Framework) . W książce korzystamy z platformy .NET (a nie z klasycznej .NET Framework).
W oknie dialogowym
Configure your new project wpisz Uqs.Arithmetic w polu
Project name i UqsMathLib w polu
Solution name , a następnie kliknij przycisk
Next . Spójrz na rysunek 1.5.
Rysunek 1.5. Okno dialogowe przeznaczone do konfiguracji nowego projektu
W oknie dialogowym
Additional information z rozwijanego menu wybierz opcję
.NET 6.0 (Long-term support) , jak pokazałem na rysunku 1.6., i kliknij przycisk
Create .
Rysunek 1.6. Okno dialogowe Additional information
W taki sposób projekt biblioteki klas został przygotowany za pomocą graficznego interfejsu użytkownika Visual Studio .
Użycie wiersza poleceń
Jeżeli preferujesz tworzenie projektu za pomocą wiersza poleceń, w tym miejscu znajdziesz polecenia, które trzeba w tym celu wydać.
Utwórz katalog o nazwie
UqsMathLib (wydaj polecenie md UqsMathLib ). W wierszu poleceń przejdź do nowego katalogu (wydaj polecenie cd UqsMathLib ), jak pokazałem na rysunku 1.7.
Rysunek 1.7. Okno wiersza poleceń zawierające niezbędne polecenia
Utwórz plik rozwiązania (z rozszerzeniem
.sln ), który zostanie wygenerowany z nazwą odpowiadającą nazwie katalogu - czyli w omawianym przykładzie to plik
UqsMathLib.sln . W tym celu wydaj następujące polecenie:
dotnet new sln
Utwórz nową bibliotekę klas o nazwie
Uqs.Arithmetic w katalogu o tej samej nazwie i użyj platformy
.NET 6.0 . Oto polecenie, które należy w tym celu wydać:
dotnet new classlib -o Uqs.Arithmetic -f net6.0
Nowy projekt dodaj do pliku rozwiązania, co odbywa się przez wykonanie przedstawionego tutaj polecenia.
dotnet sln add uqs.arithmetic
W taki sposób projekt biblioteki klas został przygotowany za pomocą wiersza poleceń.
Utworzenie projektu testów jednostkowych
W tym momencie mamy rozwiązanie zawierające tylko jeden projekt, czyli bibliotekę klas. Kolejnym zadaniem jest dodanie do naszego rozwiązania biblioteki testów jednostkowych. W tym celu skorzystamy z projektu xUnit Test Project .
xUnit.net to dostępne bezpłatnie, otwartoźródłowe narzędzie testów jednostkowych dla platformy .NET. Zostało udostępnione na licencji Apache 2. Visual Studio natywnie zapewnia możliwość dodawania i uruchamiania projektów xUnit, więc korzystanie z tego frameworka nie wymaga używania żadnego specjalnego narzędzia ani wtyczki.
Dokładne omówienie xUnit znajdziesz w rozdziale 3.
Będziemy stosować powszechnie przyjętą konwencję nadawania projektom testów jednostkowych nazw w postaci [NazwaProjektu].Tests.Unit . Dlatego też nasz projekt otrzymuje nazwę Uqs.Arithmetic.Tests.Unit .
Zaprezentuję dwa sposoby, na jakie jest możliwe utworzenie projektu testów jednostkowych. Wybierz ten, który Ci bardziej odpowiada.
Użycie graficznego interfejsu użytkownika
Aby utworzyć projekt testów jednostkowych, przejdź do okna Solution Explorer i wykonaj przedstawioną tutaj procedurę.
Prawym przyciskiem myszy kliknij plik rozwiązania (
UqsMathLib ). Wybierz opcję menu
Add/New Project... , jak pokazałem na rysunku 1.8.
Rysunek 1.8. Utworzenie nowego projektu w rozwiązaniu
W wyświetlonym oknie dialogowym wyszukaj element
xUnit Test Project , wybierz go, a następnie kliknij przycisk
Next . W polu
Project name wpisz wartość Uqs.Arithmetic.Tests.Unit . Kliknij przycisk
Next , wybierz platformę
.NET 6.0 , a następnie kliknij przycisk
Create .
W ten sposób projekt testów jednostkowych został utworzony za pomocą graficznego interfejsu użytkownika Visual Studio. Ten projekt wymaga jeszcze odwołania do biblioteki klas. Aby je dodać, wykonaj wymienione tutaj kroki.
W oknie eksploratora rozwiązań prawym przyciskiem myszy kliknij element
Dependencies projektu
Uqs.Arithmetic.Tests.Unit . Wybierz opcję menu
Add Project Reference... . Zaznacz element
Uqs.Arithmetic i kliknij przycisk
OK .
W ten sposób rozwiązanie zostało w pełni przygotowane za pomocą graficznego interfejsu użytkownika Visual Studio. Tę samą procedurę można przeprowadzić za pomocą wiersza poleceń. Dokładnie to wyjaśnię w następnym podpunkcie.
Użycie wiersza poleceń
Obecnie mamy rozwiązanie zawierające tylko jeden projekt, bibliotekę klas. Kolejnym zadaniem jest dodanie do naszego rozwiązania biblioteki testów jednostkowych.
Utwórz nowy projekt xUnit o nazwie Uqs.Arithmetic.Tests.Unit w katalogu o tej samej nazwie i zdecyduj o użyciu platformy .NET 6.0 . Oto polecenie, które trzeba wydać:
dotnet new xunit -o Uqs.Arithmetic.Tests.Unit -f net6.0
Nowy projekt dodaj do pliku rozwiązania, co odbywa się przez wykonanie przedstawionego tutaj polecenia.
dotnet sln add Uqs.Arithmetic.Tests.Unit
W ten sposób nasze rozwiązanie zawiera dwa projekty. Skoro projekt testów jednostkowych jest przeznaczony do testowania biblioteki klas, powinien mieć do niej odwołanie.
Wprawdzie projekt został utworzony za pomocą wiersza poleceń, ale nadal projekt testów jednostkowych musi zawierać odwołanie do biblioteki klas. W tym celu należy dodać odwołanie z Uqs.Arithmetic.Tests.Unit do Uqs.Arithmetic , jak pokazałem w kolejnym fragmencie kodu:
dotnet add Uqs.Arithmetic.Tests.Unit reference
Uqs.Arithmetic
Przedstawione rozwiązanie zostało w pełni przygotowane za pomocą wiersza poleceń.
Ostateczne rozwiązanie
Niezależnie od metody użytej do utworzenia rozwiązania - za pomocą graficznego interfejsu użytkownika bądź wiersza poleceń - w tym momencie będziesz mieć te same pliki. Jeżeli otworzysz rozwiązanie w Visual Studio, zobaczysz okno pokazane na rysunku 1.9.
Rysunek 1.9. Struktura ostatecznego rozwiązania
Aby rozpocząć pracę od czystego stanu, usuń plik Class1.cs . Został dodany automatycznie przez szablon i nie będziemy go używać.
Na rysunku 1.10 pokazałem logiczną strukturę dwóch naszych projektów.
Rysunek 1.10. Logiczna struktura naszych przykładowych projektów
Dotychczas utworzyliśmy dwa projekty. Pierwszy ( Uqs.Arithmetic ) będzie na pewnym etapie przekazany do środowiska produkcyjnego, natomiast drugi ( Uqs.Arithmetic.Tests.Unit ) jest przeznaczony do przetestowania tego pierwszego projektu. Plik rozwiązania zapewnia połączenie między wymienionymi projektami.
Po zakończeniu tej mniej przyjemnej fazy budowania szkieletu projektu i definiowania zależności można przystąpić do znacznie przyjemniejszych zadań, które są bezpośrednio powiązane z testami jednostkowymi.
Zapoznanie się z wbudowanymi narzędziami przeznaczonymi do przeprowadzania testów
Osiągnęliśmy stan, kiedy trzeba rozejrzeć się oraz sprawdzić, jak wykrywać i wykonywać testy. To będzie wymagało poznania dostępnych narzędzi.
Mamy już kod wygenerowany przez szablon xUnit - zapoznaj się z kodem znajdującym się w pliku UnitTest1.cs i zamieszczonym w kolejnym fragmencie kodu.
using Xunit;
namespace Uqs.Arithmetic.Tests.Unit;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}
To jest zwykła klasa C#. Fact to atrybut pochodzący z frameworka xUnit. Wskazuje on każdemu narzędziu zgodnemu z xUnit, że metoda udekorowana tym atrybutem jest metodą testu jednostkowego . Narzędzia zgodne z xUnit, np. okno Test Explorer i .NET CLI Test Command , powinny mieć możliwość znalezienia tej metody w rozwiązaniu i jej uruchomienia.
Podążając za trendem z wcześniejszej części rozdziału, dostępne narzędzia przeznaczone do przeprowadzania testów można wykorzystać na dwa sposoby - za pomocą graficznego interfejsu użytkownika oraz z poziomu wiersza poleceń.
Użycie graficznego interfejsu użytkownika
Visual Studio oferuje wyposażone w graficzny interfejs użytkownika narzędzie przeznaczone do wykrywania i wykonywania testów - ma ono postać okna o nazwie Test Explorer . Aby zobaczyć, w jaki sposób to narzędzie będzie wykrywało metody testów, z poziomu menu wybierz opcję Test/Test Explorer . Na ekranie pojawi się okno dialogowe pokazane na rysunku 1.11.
Rysunek 1.11. Okno Test Explorer wyświetlające niewykonane testy
Jak możesz zobaczyć, to narzędzie wykryło wszystkie testy istniejące w naszym rozwiązaniu oraz wyświetliło je w hierarchii Nazwa projektu/Przestrzeń nazw/Klasa/Metoda . Zwróć uwagę na wyświetlenie hierarchii w kolorze szarym oraz ze znakiem wykrzyknika. Ten znak oznacza, że testy nigdy nie zostały wykonane. Aby uruchomić te testy, możesz kliknąć przycisk uruchomienia projektu w lewym górnym rogu okna (skrót klawiszowy Ctrl+R, T - naciśnij i przytrzymaj klawisz Ctrl , a następnie w krótkich odstępach czasu naciśnij kolejno klawisze R i T ). To spowoduje skompilowanie projektu i wykonanie kodu zdefiniowanego w metodach udekorowanych atrybutem Fact . Wynik tej operacji pokazałem na rysunku 1.12.
Rysunek 1.12. Okno Test Explorer wyświetla wynik wykonania testów
Nie oczekuj żadnych fajerwerków, ponieważ mamy jedynie pusty szkielet projektu. Jednak przynajmniej testy będą oznaczone kolorem zielonym, co potwierdzi poprawność działania przygotowanego środowiska. W podobny sposób testy można wykrywać i wykonywać za pomocą wiersza poleceń.
Użycie wiersza poleceń
Testy można również wykonywać za pomocą wiersza poleceń. W tym celu należy przejść do katalogu zawierającego rozwiązanie, a następnie wydać przedstawione tutaj polecenie:
dotnet test
Efekt wykonania tego polecenia pokazałem na rysunku 1.13.
Rysunek 1.13. Polecenie .NET przeznaczone do wykrywania i wykonywania testów
Możliwość używania tego rodzaju poleceń okazuje się przydatna na późniejszych etapach pracy, gdy zachodzi potrzeba automatyzacji wykonywania testów.
Implementacja wymagań z zastosowaniem programowania sterowanego testami
Przed przystąpieniem do tworzenia jakiegokolwiek kodu rozsądne wydaje się poznanie terminologii i konwencji, aby przygotować się na słownictwo związane z testami jednostkowymi. Dlatego też pokrótce przedstawię koncepcje testowanego systemu (ang. system under test , SUT ), testów typu czerwony i zielony (ang. red/green tests ) oraz podejścia typu " przygotowanie, działanie, asercja " (ang. arrange-act-assert , AAA ). Więcej informacji na temat tej terminologii znajdziesz w późniejszych rozdziałach. Natomiast w tym miejscu przedstawię jedynie podstawy, które pozwolą na wykonanie kilku testów.
Podczas poznawania terminologii i konwencji ułatwimy sobie implementację rozwiązania. Jedyną kwestią, którą możesz uznać za nową i nietypową, jest to, że w przypadku programowania sterowanego testami najpierw tworzy się test jednostkowy, a dopiero później kod produkcyjny. To jest jeden z najważniejszych aspektów podejścia w stylu TDD i spotkasz się z nim w tym podrozdziale.
SUT
Kod tworzący produkt zwykle jest określany mianem produkcyjnego kodu źródłowego . Typowy kod tego rodzaju utworzony z zastosowaniem programowania zorientowanego obiektowo (ang. object-oriented programming , OOP ) ma postać podobną do tutaj przedstawionej.
public class NazwaKlasy
{
public Type NazwaMetody(...)
{
// Kod wykonujący użyteczne zadania.
}
// Jeszcze więcej kodu.
}
Podczas testowania tego fragmentu kodu test jednostkowy będzie wywoływał metodę o podanej nazwie ( NazwaMetody ) i sprawdzał jej sposób działania. W trakcie działania ta metoda może wywoływać inne elementy klasy, a także może używać innych klas bądź je wywoływać. Kod wykonywany przez tę metodę ( NazwaMetody ) jest określany mianem testowanego systemu (SUT) bądź testowanego kodu (ang. code under test , CUT ). Znacznie częściej można spotkać to pierwsze określenie, SUT.
Testowany system będzie oferować punkt wejścia, który następnie będzie wykorzystywany przez testy jednostkowe. Ten punkt wejścia to najczęściej metoda wywoływana z poziomu testów jednostkowych. Na rysunku 1.14 pokazałem w sposób graficzny ideę testowanego systemu i punktu wejścia.
Rysunek 1.14. Testy jednostkowe działające w SUT
W sytuacji pokazanej na rysunku 1.14 można zobaczyć kilka testów jednostkowych wywołujących ten sam punkt wejścia testowanego systemu. Dokładne omówienie koncepcji SUT znajdziesz w rozdziale 3.
Klasa testów
Zgodnie z konwencją typowa klasa testów jednostkowych używa tych samych nazw pochodzących z SUT. W kolejnym fragmencie kodu pokazałem przykład typowej klasy testów jednostkowych.
public class NazwaKlasyTests
{
[Fact]
public void NazwaMetody_Warunek1_Oczekiwanie1()
{
// Testy jednostkowe Testing wywołujące metodę o nazwie NazwaMetody.
}
// Pozostałe testy...
[Fact]
public void NazwaMetody_WarunekN_OczekiwanieN()
{
// Testy jednostkowe Testing wywołujące metodę o nazwie NazwaMetody.
}
...
}
Zwróć uwagę na to, że nazwy klasy ( NazwaKlasy ) i metody ( NazwaMetody ) w dwóch poprzednich fragmentach kodu nie są przypadkowe. Zgodnie z konwencją powinny być takie same. Aby rozpocząć przygotowanie naszych klas testujących, musimy określić nazwy klasy i metody.
Nazwa klasy
Zgodnie z wymaganiami będzie nam potrzebna klasa przeznaczona do przechowywania wszystkich metod operacji dzielenia. Nadajemy więc tej klasie nazwę Division . Jeżeli chcesz dla niej utworzyć klasę testów jednostkowych, wówczas musi mieć ona nazwę DivisionTests . Następnym krokiem jest zmiana nazwy klasy UnitTest1 na DivisionTests . To obejmuje również zmianę nazwy pliku klasy na DivisionTests.cs .
Po umieszczeniu wskaźnika myszy w dowolnym miejscu nazwy klasy w kodzie źródłowym (w omawianym przykładzie to była nazwa UnitTest1 ) należy nacisnąć klawisze Ctrl+R, R (trzymając wciśnięty klawisz Ctrl , w krótkim odstępie czasu dwukrotnie naciśnij klawisz R ). Wpisz nową nazwę, DivisionTests , i naciśnij klawisz Enter . To spowoduje także zmianę nazwy pliku, o ile zostało zaznaczone pole wyboru Rename symbol's file .
Nazwa metody
Na szczęście wymagania w omawianym przykładzie są proste, więc nazwa naszej metody to po prostu Divide . Zgodnie z wymaganiami ta metoda będzie akceptowała dwa argumenty w postaci liczb całkowitych ( int32 ) i zwróci wartość typu decimal . Kolejnym krokiem jest refaktoryzacja istniejącego testu jednostkowego z Test1 na postać DivideWarunek1_Oczekiwanie1 .
Przypomnienie związane z terminologią stosowaną w arytmetyce : w przypadku wyrażenia 10 / 5 = 2 wartość 10 to dzielna, 5 to dzielnik, 2 zaś to współczynnik.
Warunki i oczekiwania
Podczas testowania następuje określenie warunku oraz tego, co jest oczekiwane w przypadku spełnienia danego warunku. Rozpoczynamy od warunku podstawowego , nazywanego również ścieżką pozytywną bądź ścieżką szczęśliwą . Najpierw trzeba przygotować wszystkie ścieżki pozytywne, a dopiero później można przejść do innych przypadków. Nasz cel w testach jednostkowych sprowadza się do ustalenia warunku i oczekiwań oraz przygotowania testu jednostkowego dla każdego wariantu.
Aby pokazać związek między testowanymi metodami (metoda w naszym testowanym systemie) a warunkami i oczekiwaniami, wykorzystamy doskonale znaną konwencję, której przykład zastosowania jest pokazany w kolejnym fragmencie kodu.
[Fact]
public void NazwaMetody_Warunek_Oczekiwanie()
{
...
Oto kilka losowo wybranych nazw metod testów jednostkowych, które pomogą oswoić się ze wspomnianą wcześniej konwencją:
SaveUserDetails _MissingEmailAddress_EmailIsMissing ValidateUserCredentials_HashedPasswordDoesntMatch_False GetUserById_IdDoesntExist_UserNotFoundException
Więcej przykładów poznasz podczas definiowania testów jednostkowych.
Podstawowym wymaganiem jest przeprowadzenie dzielenia dwóch liczb całkowitych. Najprostsza implementacja polega na podzieleniu dwóch liczb całkowitych i otrzymaniu w wyniku również liczby całkowitej. W takim przypadku warunkiem jest istnienie podzielnych liczb całkowitych (ang. divisible integers ), oczekiwanie zaś to zwrócenie przez tę operację liczby całkowitej (ang. whole number ). Teraz należy więc uaktualnić sygnaturę naszego testu jednostkowego do postaci Divide_DivisibleIntegers_WholeNum ber oraz zdefiniować tę metodę w sposób przedstawiony w kolejnym fragmencie kodu.
[Fact]
public void Divide_DivisibleIntegers_WholeNumber()
{
int dividend = 10;
int divisor = 5;
decimal expectedQuotient = 2;
decimal actualQuotient = Division.Divide(dividend,
divisor);
Assert.Equal(expectedQuotient, actualQuotient);
}
Ten kod nie skompiluje się, ponieważ na tym etapie klasa Division jeszcze nie istnieje. Doskonale o tym wiemy, bo pod nazwą klasy Division znajduje się falista linia. To jest ten rzadki przypadek, w którym niemożliwość skompilowania klasy ze względu na brak pewnego komponentu nie jest czymś złym. W ten sposób otrzymujemy informację, że test zakończył się niepowodzeniem , co w tym przypadku również jest dobrą wiadomością.
Wprawdzie wydaje się głupie zakończenie testu niepowodzeniem z powodu braku możliwości skompilowania kodu, ponieważ klasa Division nie istnieje, ale to jednocześnie oznacza, że nie został utworzony kod testowanego systemu. W rozdziale 5. dowiesz się więcej na temat uwzględniania tego przypadku.
Assert to klasa pochodząca z frameworka xUnit. Metoda statyczna Equal jest wielokrotnie przeciążana, w omawianym kodzie zaś użyto wersji o następującej sygnaturze:
public static void Equal<T>(T expected, T actual)
Po uruchomieniu ta metoda będzie sygnalizowała frameworkowi xUnit, że wartości oczekiwana i faktycznie otrzymana nie są takie same. Jeżeli po wykonaniu testu wynikiem tej asercji jest true , to oznacza zaliczenie testu.
Czerwony - zielony
Niepowodzenie jest tym, co nas najbardziej interesuje. W późniejszych rozdziałach wyjaśnię, dlaczego tak się dzieje. W tym miejscu wystarczy wiedzieć, że pracę trzeba rozpocząć od nieudanej budowy (kompilacji) bądź testu zakończonego niepowodzeniem (nieudana asercja), a następnie doprowadzić do jego zaliczenia. Podejście typu niezaliczony-zaliczony jest również określane mianem techniki refaktoryzacji czerwony - zielony , która odzwierciedla ideę zły - dobry i stój - idź .
Konieczne jest dodanie klasy Division oraz metody Divide , a także utworzenie minimalnej ilości kodu, dzięki któremu test zostanie zaliczony. W projekcie Uqs.Arithmetic utwórz nowy plik o nazwie Division.cs i przedstawionej tutaj zawartości.
namespace Uqs.Arithmetic;
public class Division
{
public static decimal Divide(int dividend, int divisor)
{
decimal quotient = dividend / divisor;
return quotient;
}
}
Wskazówka
Klasę można utworzyć przez umieszczenie wskaźnika w dowolnym miejscu nazwy klasy (w omawianym przykładzie to Division ) i naciśnięcie klawiszy Ctrl+. (trzymając wciśnięty klawisz Ctrl , naciśnij klawisz przedstawiający kropkę). Wybierz opcję Generate new type... , a następnie z rozwijanego menu Project wybierz Uqs.Arithmetic i naciśnij przycisk OK . Dalej, aby wygenerować metodę, umieść wskaźnik w klasie Divide i naciśnij klawisze Ctrl+. , wybierz opcję Generate method 'Division.Divide' , a otrzymasz w klasie Division szkielet metody gotowy do wypełnienia własnym kodem.
Trzeba koniecznie pamiętać, że w kodzie C# wynikiem dzielenia dwóch liczb całkowitych jest liczba całkowita . Spotykałem się z sytuacjami, w których starsi programiści zapominali o tym, co z kolei prowadziło do poważnych konsekwencji. W zaimplementowanym kodzie zostało uwzględnione jedynie dzielenie liczb całkowitych, które prowadzi do wyniku w postaci liczby całkowitej. To powinno pozwolić na zaliczenie testu.
W tym momencie jesteśmy gotowi do wykonania testów za pomocą okna Test Explorer w Visual Studio. Naciśnij więc klawisze Ctrl+R, A , aby w ten sposób skompilować projekty, a następnie wykonać wszystkie znajdujące się w nich testy (obecnie to tylko jeden). Zauważ, że okno Test Explorer wskazuje kolor zielony, a między nazwą testu i atrybutem Fact znajduje się zielona ikona. Jej kliknięcie spowoduje wyświetlenie pewnych opcji związanych z testami, jak pokazałem na rysunku 1.15.