W poprzednim poście zapoznaliśmy się z pojęciem “mock”. Dzisiaj krok po kroku napiszemy pierwszy test jednostkowy z wykorzystaniem ASP.NET MVC, nUnit oraz RhinoMocks. Do dzieła.
1) Tworzymy projekt ASP.NET MVC
Z odpowiedniej strony ściągamy instalator i… instalujemy. W VS wchodzimy w okno tworzenia nowego projektu i w sekcji Web wybieramy aplikację ASP.NET MVC. Po podaniu nazwy i lokalizacji kreator spyta nas czy utworzyć projekt dla testów jednostkowych. Jak widać domyślnie na liście frameworków do wyboru znajduje się jedynie (surprise!) Visual Studio Unit Test. Tego nie chcemy, zatem rezygnujemy z takiego projektu i przechodzimy dalej.
2) Modyfikujemy projekt ASP.NET MVC
Domyślna zawartość projektu utworzona z szablonu jest pewnym punktem wyjścia, jednak tak naprawdę nie nadaje się właściwie do niczego. Ani to edukujące, ani to godne naśladowania… Moim zdaniem zespół mógł się bardziej postarać i stworzyć coś, na czym można by się wzorować. Ale nieważne.
Zmodyfikujemy zawartość projektu tak, aby pasowała do przedstawionego ostatnio testu funkcjonalności zalogowania. Funkcjonalność ta nie powinna być moim zdaniem w całości obsłużona w kontrolerze, tak jak to generuje nam kreator. Dodam więc do projektu nowy katalog, ServiceLayer, i umieszczę w nim interfejs przedstawiony poprzednim razem. AccountController wyczyszczę z kolei tak, aby ustrzec się antywzorca Fat Controller (i przy okazji uniknąć tworzenia kilku niepowiązanych klas w jednym pliku, jak to jest domyślnie wygenerowane…). Usunąłem też metody odpowiedzialne za rejestrację, zmianę hasła itd: nie są nam one teraz potrzebne. Całość prezentuje się tak:
3) Tworzymy projekt dla testów
Do solucji dodajemy drugi projekt, zwykle jego nazwa to <nazwa_testowanego_projektu>.Tests. Jest to zwykła biblioteka, zatem z szablonów projektów wybieramy Windows->Class Library. Po usunięciu Class1.cs dodajemy referencję do testowanego projektu.
4) Dodajemy nUnit
Jako framework do testów jednostkowych wybieram najpopularniejszy chyba od dawna nUnit. Ze strony projektu ściągamy najnowszą wersję (aktualnie 2.5). Zawsze w miarę możliwości staram się raczej ściagać binaria niż instalatory, ale co kto woli. Po ściągnięciu pliku NUnit-2.5.0.9122.zip rozpakowuję go i do projektu z testami dodaję refencję do <nUnit>\bin\net-2.0\framework\nunit.framework.dll.
5) Dodajemy Rhino Mocks
Mój ulubiony framework do tworzenia mock objects to Rhino Mocks autorstwa genialnego Ayende Rahien. Ze strony projektu ściągam więc najnowszą wersję (aktualnie 3.5). Mała uwaga: na stronie zawartych jest kilka “opcji”. W tym przypadku potrzebna jest zwykła “Rhino Mocks 3.5 – For .Net 3.5“. (biblioteka ta korzysta z innego darmowego projektu, Castle Project, i wersja “with Castle assemblies” zawiera po prostu jego dllki jako osobne pliki, a nie połączone z assembly RhinoMocks jak w opcji podstawowej). Po rozpakowaniu dodaję referencję do Rhino.Mocks.dll. Teraz nasz projekt jest w pełni przygotowany na przyjęcie testów (dodatkowo usunąłem zbędne referencje; nie trzeba tego robić, ale nie lubię jak mi się tam plączą):
6) Piszemy test
Zacznijmy od testu sprawdzającego to samo co poprzednim razem – czyli że akcja LogOn w kontrolerze AccountController wywołuje odpowiednią metodę w odpowiedniej usłudze z odpowiednimi paramterami. Ostatnio trzeba się było trochę namęczyć pisząc własnego mocka; teraz dzięki Rhino Mocks sprawa jest banalna:
Dlaczego test wygląda tak a nie inaczej, co to jest AssertWasCalled, czy entery w tych a nie innych miejscach są postawione celowo czy niechcący… o tym w przyszłości. Dzisiaj chodzi o napisanie testu stanowiącego bazę do ewentualnych dalszych samodzielnych zabaw do momentu ukazania się kolejnej części.
7) Uruchamiamy test
Testy można uruchomić na wiele sposobów. Zaprezentuję dwa z nich:
1) nUnit test runner
Wraz z nUnit ściągnęliśmy niechcący program do uruchamiania testów napisanych przy użyciu tego frameworka. Znajdziemy go tutaj: <nUnit>\bin\net-2.0\nunit.exe. Korzystanie z niego jest banalne. Pierwsze co robimy do włączamy wsparcie dla Visual Studio (Tools –> Settings –> IDE Support –> Visual Studio –> Enable Visual Studio Support –> OK). Po tej operacji menu File –> Open Project pozwoli nam na wybranie pliku .sln i wszystkie projekty w naszej solucji zawarte zostaną automatycznie dodane do testowania. Klikamy Run i… to wszystko! Kiedyś byłem nawet tak miły że napisałem jak dodać do Visual Studio guzik uruchamiający nUnit dla aktualnie otwartej solucji:) (Visual Studio Express & NUnit).
(piękny zielony pasek oznacza, że wszystkie testy przeszły; czerwone kółka w lewym panelu spowodowane są brakiem testów w projekcie testowanym, można taki brzydki efekt wyeliminować wybierając plik .csproj projektu testującego zamiast .sln całej solucji)
2) Resharper
W tym przypadku filozofia jest po prostu ŻADNA. Klikamy zielone kółko obok testu bądź całej testowanej klasy i tyle.
Dodatkowo polecam utworzenie skrótów klawiszowych dla komend ReSharper.UnitTest_RunSolution oraz ReSharper.UnitTest_ContextRun.
8) Eksperymentujemy
Ten punkt pozostawiam do samodzielnego wykonania zainteresowanym Czytelnikom. Co się stanie jeśli przekażemy zmieniony parametr do metody? A co się stanie jak wywołamy metodę dwa razy? A co się stanie jeśli nie wywołamy metody? I tak dalej i tak dalej… Ciekawość to pierwszy stopień do sukcesu.
Miłej zabawy życzę. Zwracam jednocześnie uwagę, że dzięki temu możemy stworzyć warstwę kontrolerów nie dotykając póki co żadnej logiki! Mamy jedynie interfejs usługi odpowiedzialnej za uwierzytelnienie, ale nie zaczęliśmy nawet implementować klasy która będzie to robiła naprawdę. Zdefiniowaliśmy tylko czego od niej będziemy oczekiwać w przyszłości, a w jaki sposób zostanie to zrealizowane – póki co nie ma znaczenia. Mimo to wiemy, że nasz kontroler działa, chociaż wejście na stronę skończy się BUM.
Super :) Brakowało takiego cyklu, zwłaszcza po polsku. Jako użytkownik Moq z chęcią przypatrzę się Rhino.Mocks :)
Szybko wypuszczasz kolejne części, fajnie :) Oby dalej w takim tempie!
Znalazłem właśnie, że do MVC można doinstalować template do różnych innych frameworków do unit testów (w tym też do NUnit), jeśli komuś potrzeba to: http://www.nikmakris.com/blog/2009/05/setting-up-aspnet-mvc-with-nunit-for.html