Jak ustrukturyzować testy jednostkowe dla aplikacji GUI przy użyciu C # i NUnit

16

Zostałem poproszony o wykonanie małego projektu pobocznego, aby dostarczyć prostą aplikację jednemu z naszych klientów. Normalnie pracowałbym nad kodem zaplecza, w którym mam wszystkie moje potrzeby związane z testowaniem, i nie miałem jeszcze wątpliwej przyjemności pisania testów dla GUI, więc nie jest dla mnie jasne, jak powinienem skonfigurować kod testujący i narzędzia dla EXE.

Moim pierwszym instynktem było po prostu dołączenie testów z kodem aplikacji, jednak wymagałoby to podania szeregu zależnych od testu zależności, których poinstruowano mnie, aby nie wysyłać do klienta. Nie jestem również w stanie wydobyć żadnej gotówki za specjalnie zaprojektowane narzędzie testowe, więc muszę użyć narzędzi, które mam pod ręką ( StoryQ , RhinoMocks i NUnit), co naprawdę powinno wystarczyć do przetestowania działania prostej aplikacji GUI. Z tego, co widzę, pozostawia mi to próbę znalezienia właściwej równowagi między utrzymaniem projektu naprawdę prostym lub celowym nadmiernym opracowaniem na potrzeby testów. Wygląda na to, że albo buduję aplikację z logiką biznesową w osobnej bibliotece i testuję bibliotekę, jak zwykle, albo znajduję jakiś inny mechanizm, który pozwala mi na wykonanie pliku bez rozbijania dodatkowych modułów, których projekt aplikacji nie ma naprawdę potrzebuję.

Edycja:
Należy pamiętać, że to pytanie dotyczy sposobu strukturyzowania relacji między NUnit a moim plikiem wykonywalnym - w przeciwieństwie do biblioteki DLL - a nie sposobu oddzielenia prezentacji i logiki biznesowej.
/Edytować

Więc moje pytanie brzmi:

  1. Czy istnieje konkretna / zalecana metoda konfiguracji prostej aplikacji GUI z testami jednostkowymi, która pozwala mi odpowiednio sprawdzić stan i zachowanie, używając dostępnych narzędzi i bez nadmiernej inżynierii?
  2. Czy przeoczyłem coś fundamentalnego w sposobie, w jaki NUnit powinien być wywoływany / konfigurowany podczas testowania EXE (w przeciwieństwie do DLL)?
  3. Czy możesz podać lub wskazać mi przykłady, jak to wszystko osiągnąć?

Zdaję sobie sprawę, że może to być więcej niż jeden sposób, dlatego szukam konkretnych wskazówek dotyczących implementacji w oparciu o twoje doświadczenia.

S.Robins
źródło
NUnit nie jest przeznaczony do bezpośredniego testowania GUI. Musisz oddzielić warstwę prezentacji (tj. Widok) od danych i logiki biznesowej (tj. Model), abyś mógł przetestować to, co wchodzi do twojego widoku bez korzystania z widoku.
Bernard,
1
@Bernard To pytanie nie dotyczy nakładania GUI na testy. Oczywiście wszystkie moje aplikacje - nawet te trywialne - nakładam warstwowo, więc to naprawdę nie jest dla mnie problem. Zredagowałem pytanie, aby pasowało, i mam nadzieję, że rozwiąże to wszelkie nieporozumienia. :)
S.Robins,
1
Nie ma nic strasznie skomplikowanego w testowaniu jednostkowym w plikach EXE. Po prostu spraw, by testowa biblioteka DLL odwoływała się do pliku EXE i możesz zacząć.
whatsisname

Odpowiedzi:

3

W jednym z moich komentarzy do odpowiedzi simoramana wspomniałem, że wymyśliłem kilka sposobów, aby to zrobić. Jedna z moich opcji była podobna do sugestii w odpowiedzi Jalayna, aby utworzyć duplikat projektu i wygenerować bibliotekę DLL, podczas gdy moim drugim pomysłem było po prostu połączenie z plikami w projekcie, w którym znajdował się kod, który chciałem przetestować. Chociaż obie opcje mogą sprawić, że zadziałają, są one mniej niż idealne.

W drugim przypadku miałbym do czynienia z bałaganem zależności jednostek, chyba że naprawdę mogłem rozdzielić architekturę w celu zminimalizowania zależności. Jest to dobre w przypadku mniejszych projektów, ale większe mogą z łatwością stać się prawdziwym bałaganem do zarządzania. Jednak moim największym oporem wobec tej opcji jest sama nieelegancja. Jasne, że mógłbymaby działało, ale robiąc to, muszę skutecznie przerwać enkapsulację, aby przetestować wewnętrzne elementy zestawu bezpośrednio przez źródło, zamiast testować za pośrednictwem publicznych interfejsów, co moim zdaniem jest dużym nie-nie. Podobnie posiadanie dodatkowego pliku projektu oznaczałoby albo duplikowanie wysiłków w dwóch projektach na raz, albo znalezienie sposobu na automatyczne dodanie ustawień pliku projektu do dwóch plików na raz, lub pamiętanie o kopiowaniu i zmianie nazwy pola projektu za każdym razem, gdy buduję. Może to być zautomatyzowane na serwerze kompilacji, ale zarządzanie IDE byłoby uciążliwe. Znowu może działać, ale w najlepszym wypadku jest to kludge, a gorzej, jeśli się pomylisz.

Wydaje się, że najlepszym sposobem jest zrobienie tego, co skomentowała nazwa mojego pytania, i po prostu włączenie EXE jako referencji w projekcie testowym. Okazuje się, że w tym przypadku EXE jest skutecznie traktowany tak samo jak DLL, i jestem w stanie uzyskać dostęp do wszystkich moich klas warstwowych , aby przetestować wszystko, co płynie moją łodzią.

S.Robins
źródło
2

Myślę, że:

  • Kod testu biznesowego powinien znajdować się w osobnym projekcie testującym bibliotekę kodów biznesowych.
  • Kod testowy GUI powinien znajdować się w osobnym projekcie, testującym bibliotekę GUI. Teraz, jak zbudować bibliotekę GUI zamiast pliku wykonywalnego, próbuję odpowiedzieć na to później.
  • Jeśli masz my.namespace.biz.MyClass, twoją klasą testową powinna być my.namespace.biz.MyClassTest (lub MyClassTestCase).
  • Jeśli chcesz przetestować kod znajdujący się w docelowym pliku wykonywalnym, powinieneś mieć instalację, która buduje EXE, i inną instalację, która buduje bibliotekę (DLL), na której uruchomisz swoje testy.

Są to zasady, które lubię stosować, niezależnie od tego, czy jest to Java, czy C # (oczywiście, że nie ma problemu z Javą w Javie :-))

Jeśli chodzi o konfigurację środowiska testowego, wydaje mi się, że masz przynajmniej te dwie opcje:

Korzystanie z MSBuild

Utwórz klon pliku .proj (powiedz myproject-as-dll.proj ). Zmień OutputTypesklonowany plik z „ EXE” na „ Library”. Za pomocą polecenia MSBuild możesz teraz utworzyć bibliotekę, którą możesz ustawić jako odniesienie w swoim projekcie zawierającą przypadki testowe NUnit.

Wydaje mi się to możliwe, ale nigdy nie używałem go tak szczerze, więc nie jestem pewien. Ponadto możesz nie mieć MSBuild na serwerze testowym integracji i nie wiem, czy można go oddzielić od Visual Studio ...

Korzystanie z NAnt

Jeśli nie jesteś zaznajomiony z NAnt, będziesz musiał przejść do Google, jak skonfigurować z nim kompilacje projektu. Może sprawdź to , że jest trochę stary, ale autor skomentował pliki NANT Jeśli go znaleźć i wymowne (. Edit: badając jego akta bardziej szczegółowo, znaleźć swój plik konfiguracyjny niezwykle wielokrotnego użytku ). Robi także znacznie więcej niż tylko kompilację, ponieważ wykonuje przypadki testowe i uruchamia narzędzia do pokrywania kodu. Przyznaję, że nigdy nie korzystałem z NAnt, w przeciwieństwie do jego odpowiednika w Javie i ojca „Anta”, z którego często korzystałem, ale widzę, że to całkiem to samo i nie sądzę, że jest to trudne do nauczenia się.

Za pomocą tego narzędzia możesz wymyślić konfigurację, która pozwoli Ci:

  • zbuduj wszystkie swoje projekty (logikę biznesową, GUI itp.) w osobnych bibliotekach
  • buduj swoje projekty testowe
  • uruchomić testy (ta konkretna część jest wykonywana za pomocą zadania NUnit2 ).
  • sprawdź zasięg kodu w zadaniu NCover .

Przy odrobinie więcej kodu możesz nawet:

  • wykonuj nocne wdrożenia na serwerze integracyjnym
  • jeśli NAnt jest dostępny na serwerze integracyjnym, uruchom nocne testy integracyjne za pomocą zaplanowanych zadań

Wszystko odbywa się bez zmiany czegokolwiek w plikach Visual Studio. I tak naprawdę nie wygląda mi to na nadmierną inżynierię, to tylko jeden plik. Może to potrwać jeden, może dwa dni, aby wszystko działało, ale moim zdaniem będziesz mieć dobrą konfigurację.

Na koniec dałbym klientowi wszystko, co niezbędne do zbudowania, przetestowania i uruchomienia projektów. Wydaje mi się, że pokazuje to twój profesjonalizm i fakt, że piszesz kod z myślą o jakości (co wydaje mi się, że robisz, ponieważ szukasz eleganckich rozwiązań)

Jalayn
źródło
0

Tylko dlatego, że projekt jest mały (początkowo), nie oznacza, że ​​odpowiednia architektura jest nadmiernie inżynierska. Fakt, że chcesz pisać testy, świadczy o tym, że Twój projekt nie jest całkowicie trywialnym jednorazowym włamaniem.

Nie wspomniałeś, którego GUI-Framework używasz. WPF MVVM (Model-View-ViewModel) jest dobry i pozwala dość łatwo pisać testy dla całej logiki. Dzięki WinForms słyszałem dobre rzeczy o MVP (Model-View-Presenter)

simoraman
źródło
Piszę testy dla całego kodu, który piszę. Nawet rzeczy, które możesz uznać za trywialne. Jedyny raz, kiedy nie piszę testu, to kiedy mam skok. W tym przypadku wysyłam klientowi jednorazowe narzędzie, więc testowanie to coś więcej niż luksus, jest to warunek spełnienia naszych standardów jakości. Jeśli chodzi o „nadmierną inżynierię”, nie jest to wybór między dobrą lub złą architekturą, ale raczej unikanie potrzeby narzucania dodatkowych warstw, które nie są wymagane w tym przypadku, ponieważ aplikacja ma jeden cel i stosunkowo krótki cykl życia.
S.Robins,
Jeśli chodzi o wybór gui-framework, nie widzę, jak wpłynie to na sposób konfiguracji środowiska testowego. Szukam JAK konkretnie wdrożyć testy jednostkowe dla warstwy GUI za pomocą dostępnych narzędzi. Ta konkretna odpowiedź tak naprawdę nic mi na ten temat nie mówi.
S.Robins,
Simoraman - Jeśli zabierzesz raczej osądzający pierwszy akapit, będzie to zmierzać do odpowiedzi. Napraw to, a usunę moje -1. @ S.Robins zauważa, że ​​drugi akapit jest istotny - choć nie pełna odpowiedź, pomogłaby. Jeśli twoja warstwa GUI jest cienka, dobrze ustrukturyzowana i oczywista, a cała logika biznesowa jest testowana za pomocą testów jednostkowych na poziomie Modelu, być może nie musisz wykonywać dodatkowych czynności związanych z jawnym testowaniem interfejsu użytkownika.
Mark Booth,
1
@MarkBooth Layering nie jest tak naprawdę problemem. Jak wspomina simiraman, mogę MVP, MVVM lub zbudować coś jeszcze cieńszego. Mam jednak pewne elementy GUI, które będą wymagały jawnego testowania, dlatego postanowiłem napisać to jako pytanie. Mam kilka pomysłów, a jeśli pogorszy się, wiem, że w końcu będę w stanie rozwiązać problem i sam napisać odpowiedź. Chciałem jednak otworzyć to na społeczność, ponieważ pomyślałem, że będzie to dobre pytanie dla ProgrammersSE. ;-)
S.Robins
0

Spójrz na moją odpowiedź na to pytanie: Jak skonfigurować MVP dla rozwiązania Winforms?

Napisałem przykładową aplikację, która pokazuje, w jaki sposób nakładam warstwy i jak testuję, mój GUI.

czytanie twojej edycji: użyj testera, który integruje się ze środowiskiem programistycznym. Używam ReSharper.

Bryan Boettcher
źródło
Dzięki za rekomendację ReSharper. To narzędzie, którego używam podczas programowania. Niestety nie pomoże to podczas wykonywania testów na serwerze kompilacji integracji. Nie mówi mi również, jak skonfigurować testy Nunit, aby uzyskać dostęp do kodu w pliku exe podczas testowania.
S.Robins
1
Nieformalnie tak. Plik exe to tylko widok, który ładuje prezentera, modele i modele widoków z biblioteki klas w ramach uruchamiania aplikacji. Przynajmniej w moim rozwiązaniu widok jest na tyle głupi, że nie testujemy go za pomocą testów automatycznych, a jedynie wykonujemy testy akceptacyjne, aby upewnić się, że wszystko jest poprawnie napisane i przyciski są tam, gdzie powinny być. Testowanie biblioteki dll przez NUnit jest bardzo łatwe.
Bryan Boettcher
0

Napisałem Nunit WinForms kilka lat temu (chyba 6 lat). Jedną rzeczą, którą szczególnie pamiętam, jest to, że chociaż jest to jednostkowy przypadek testowy, działa on również jako przypadek końcowy. Czasami nie ma wiele do przetestowania na interfejsie (prosty formularz). Nawet jeśli próbujesz sprawdzić, czy po kliknięciu przycisku pojawia się okno komunikatu, nieumyślnie testujesz różne inne metody z innych warstw. Jest kilka rzeczy, których nie można również zautomatyzować. Wygląd, działanie i użyteczność nie mogą być zautomatyzowane przy użyciu zautomatyzowanych testów jednostkowych. Będziesz musiał uruchomić kilka testów ręcznych przed wydaniem.

ViSu
źródło
Jeśli klient określi, że ekran powinien wyglądać w określony sposób lub powinien się zmieniać w określony sposób, należy przetestować te rzeczy. Przechwytywanie specyfikacji jako testów jest sercem metodologii BDD i nigdy nie znalazłem sytuacji, w której nie można - choć twórczo - znaleźć sposobu na zautomatyzowanie testu. Prawdziwe pytanie brzmi, czy testowanie będzie miało wartość, czy aplikacja jest wystarczająco dobrze uwzględniona, aby umożliwić zautomatyzowanie wszystkich testów i czy testy będą opłacalne. Zgadzam się jednak, że czasami tak nie jest.
S.Robins