Średni · lekcja 3

Testy jednostkowe w aplikacji desktopowej WPF

Aplikacja WPF ma okna, przyciski i pola tekstowe — a testów jednostkowych NIE piszemy dla wyglądu interfejsu. Sekret polega na tym, żeby logikę biznesową (obliczenia, walidację, reguły) trzymać w OSOBNEJ warstwie, niezależnej od okien — dokładnie tak, jak robi...

Zacznij tutaj

Po co się tego uczymy?

Aplikacja WPF ma okna, przyciski i pola tekstowe — a testów jednostkowych NIE piszemy dla wyglądu interfejsu. Sekret polega na tym, żeby logikę biznesową (obliczenia, walidację, reguły) trzymać w OSOBNEJ warstwie, niezależnej od okien — dokładnie tak, jak robi to wzorzec MVVM poznany wcześniej w dziale WPF. Dzięki temu możesz przetestować "mózg" aplikacji dokładnie tym samym MSTestem, którego użyłeś w lekcji 2, mimo że tym razem aplikacja ma pełny graficzny interfejs.

Wprowadzenie

Teoria

Krok po kroku — budowa rozwiązania z trzema projektami:

  1. Otwórz istniejący projekt WPF (albo utwórz nowy jak w lekcji o pierwszej aplikacji WPF, dział Aplikacje desktopowe).
  2. Dodaj bibliotekę logiki: prawym przyciskiem na ROZWIĄZANIE → Dodaj → Nowy projekt → wyszukaj Class Library → wybierz "Biblioteka klas (.NET)" → nazwij np. KalkulatorApp.Logika → Utwórz.
  3. Podepnij bibliotekę do aplikacji WPF: prawym przyciskiem na projekt WPF → Dodaj → Odwołanie do projektu… → zaznacz KalkulatorApp.Logika → OK.
  4. Dodaj projekt testowy: prawym przyciskiem na ROZWIĄZANIE → Dodaj → Nowy projekt → wyszukaj MSTest → nazwij np. KalkulatorApp.Tests → Utwórz.
  5. Podepnij projekt testowy WYŁĄCZNIE do biblioteki Logika (nie do WPF!): prawym przyciskiem na KalkulatorApp.Tests → Dodaj → Odwołanie do projektu… → zaznacz KalkulatorApp.Logika → OK.
  6. Przenieś (albo od razu napisz) klasy z logiką biznesową w projekcie Logika, testy w projekcie Tests, uruchom przez Test → Uruchom wszystkie testy.

Kluczowa zasada: testujemy Logikę, nie UI. Okna, przyciski, kolory, style — to wygląd, nie zachowanie, i nie da się (ani nie warto) tego sensownie testować jednostkowo. Natomiast KAŻDA reguła biznesowa (obliczenia, walidacja, decyzje "co się stanie, gdy...") powinna dać się przetestować BEZ uruchamiania jakiegokolwiek okna.

Jak to osiągnąć — oddzielenie Logiki od UI (przypomnienie z wzorca MVVM). Cała logika biznesowa trafia do zwykłych klas C# (np. w folderze/projekcie Logika/), które NIE mają żadnego odwołania do WPF, okien czy kontrolek. ViewModel korzysta z tych klas i WYSTAWIA ich wyniki do UI przez bindowanie, ale sam nie zawiera skomplikowanej logiki — tylko "klej" łączący Logikę z Widokiem.

Co można testować w takiej architekturze:

  • Metody zwracające wartość — czy wynik jest poprawny (np. obliczenia kalkulatora).
  • Metody obliczeniowe — wszelkie przeliczenia, logika biznesowa.
  • Walidację danych — czy metoda poprawnie wykrywa błędne dane wejściowe.
  • Funkcje rzucające wyjątek — np. czy dzielenie przez zero rzuca DivideByZeroException.
  • Metody typu true/false — np. logika sprawdzająca hasło, wiek, uprawnienia.

Struktura projektu z warstwą testowalną. Typowe rozwiązanie w Visual Studio: trzy projekty w jednym rozwiązaniu — NazwaAplikacji (właściwa aplikacja WPF z oknami XAML), NazwaAplikacji.Logika (biblioteka klas z czystą logiką, bez zależności od WPF) i NazwaAplikacji.Tests (projekt MSTest z odwołaniem TYLKO do biblioteki Logika — nie musi w ogóle "widzieć" WPF).

Dodatkowe polecenia MSTest — dane parametryczne. [DataTestMethod] razem z [DataRow(...)] pozwala uruchomić JEDEN test z WIELOMA zestawami danych wejściowych, zamiast kopiować niemal identyczny test kilka razy — np. sprawdzenie tej samej metody dla kilku różnych par liczb.

Zobacz zależności

Schemat

Rozwiązanie WPF (Solution)
 ├── KalkulatorApp/                (WPF: okna XAML, MainWindow.xaml.cs)
 │     └── odwołuje się do ↓
 ├── KalkulatorApp.Logika/         (biblioteka klas, BEZ odwołania do WPF)
 │     └── LogikaKalkulatora.cs
 └── KalkulatorApp.Tests/          (MSTest, odwołanie TYLKO do Logika)
       └── LogikaKalkulatoraTests.cs

  MainWindow.xaml  ──bindowanie──▶  ViewModel  ──wywołuje──▶  LogikaKalkulatora
       (UI, NIE testujemy)      (cienki "klej")      (logika, TESTUJEMY tutaj)

Połącz z praktyką

Przykład z życia

Wyobraź sobie kalkulator: dziś działa poprawnie, ale jutro dopiszesz nową funkcję i nagle 2+2 daje 5. Bez testów zauważysz to dopiero, gdy ktoś zgłosi błąd — z testami dowiesz się o tym NATYCHMIAST po zmianie kodu, jeszcze zanim ktokolwiek uruchomi aplikację. To dokładnie ta sama korzyść, którą testy dają profesjonalnym zespołom programistycznym: możliwość zmiany kodu BEZ STRACHU, że coś po cichu przestało działać.