1) Wprowadzenie: co to są testy i po co mi to na INF.04?
Wyobraź sobie prosty kalkulator. Dziś działa, ale jutro coś dopiszesz i nagle 2+2 wyjdzie 5. Testy jednostkowe to małe automatyczne programy, które sprawdzają, czy Twoje metody robią to, co trzeba.
Dzięki testom:
- szybko widzisz błędy, zanim oddasz projekt,
- możesz bez strachu zmieniać kod (testy krzykną, jeśli coś zepsujesz),
- na egzaminie INF.04 pokażesz dojrzałe podejście: logika oddzielona od UI + testy logiki.
(To dokładnie ta idea, którą opisujesz już na BiteDu; tu doprecyzowuję i układam wszystko pod lekcję oraz pod MSTest w trybie offline.) bitedu.pl
2) Zasada AAA – najprościej
Każdy test składa się z trzech kroków:
- Arrange – przygotuj dane (np. liczby 2 i 3),
- Act – uruchom metodę (np.
Dodaj(2,3)), - Assert – sprawdź wynik (
5). bitedu.pl
To wszystko. Serio.
3) Nasza przykładowa aplikacja
Zbudujemy mini-logikę kalkulatora:
- dodawanie dwóch i trzech liczb,
- odejmowanie dwóch i trzech liczb.
Logikę trzymamy w pliku w folderze Logika, UI (WPF lub MAUI) to tylko „skórka”. Dzięki temu testujemy czystą logikę, bez uruchamiania okien.
Struktura rozwiązania (proponowana)
KalkulatorApp.sln
│
├─ KalkulatorApp/ ← projekt aplikacji (WPF lub MAUI)
│ ├─ Modele/
│ ├─ Walidacja/
│ ├─ Logika/
│ │ └─ Kalkulator.cs
│ ├─ MainWindow.xaml /.cs ← WPF wariant
│ └─ MainPage.xaml /.cs ← MAUI wariant
│
└─ KalkulatorApp.Tests/ ← projekt testowy MSTest (.NET)
└─ KalkulatorTests.cs
4) Wdrożenie krok po kroku (OFFLINE, MSTest, Visual Studio)
Krok A. Utwórz projekt aplikacji
- WPF: Nowy projekt → „Aplikacja WPF (.NET)”
- .NET MAUI: Nowy projekt → „.NET MAUI App”
Nazwij projekt: KalkulatorApp.
Krok B. Dodaj folder i klasę logiki
📁 Logika/Kalkulator.cs
namespace KalkulatorApp.Logika
{
public static class Kalkulator
{
// Dodawanie dwóch liczb
public static int Dodaj2(int a, int b) => a + b;
// Dodawanie trzech liczb
public static int Dodaj3(int a, int b, int c) => a + b + c;
// Odejmowanie dwóch liczb (a - b)
public static int Odejmij2(int a, int b) => a - b;
// Odejmowanie trzech liczb (a - b - c)
public static int Odejmij3(int a, int b, int c) => a - b - c;
}
}
Świadomie zero zależności od UI. Taka klasa nadaje się idealnie do testów.
Krok C. Dodaj projekt testowy MSTest (bez sieci)
- PPM na Rozwiązanie → Dodaj → Nowy projekt
- Wybierz szablon „Projekt testów MSTest (.NET)” (oficjalny szablon VS; nie wymaga internetu).
- Nazwij: KalkulatorApp.Tests → Utwórz.
- PPM na KalkulatorApp.Tests → Dodaj → Odwołanie… → zaznacz KalkulatorApp → OK. bitedu.pl
Krok D. Napisz testy
📄 KalkulatorApp.Tests/KalkulatorTests.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
using KalkulatorApp.Logika;
namespace KalkulatorApp.Tests
{
[TestClass]
public class KalkulatorTests
{
// AAA: Arrange-Act-Assert w praktyce
[TestMethod]
public void Dodaj2_2plus3_Zwraca5()
{
// Arrange
int a = 2, b = 3;
// Act
int wynik = Kalkulator.Dodaj2(a, b);
// Assert
Assert.AreEqual(5, wynik);
}
[TestMethod]
public void Dodaj3_1plus2plus3_Zwraca6()
{
int wynik = Kalkulator.Dodaj3(1, 2, 3);
Assert.AreEqual(6, wynik);
}
[TestMethod]
public void Odejmij2_10minus4_Zwraca6()
{
int wynik = Kalkulator.Odejmij2(10, 4);
Assert.AreEqual(6, wynik);
}
[TestMethod]
public void Odejmij3_10minus3minus2_Zwraca5()
{
int wynik = Kalkulator.Odejmij3(10, 3, 2);
Assert.AreEqual(5, wynik);
}
// Wzór z danymi parametrycznymi (DataRow) – opcjonalnie, jeśli szablon MSTest to wspiera
[DataTestMethod]
[DataRow(0, 0, 0)]
[DataRow(-1, 1, 0)]
[DataRow(100, 200, 300)]
public void Dodaj2_RozneWartosci_ZwracaSume(int a, int b, int oczekiwany)
{
Assert.AreEqual(oczekiwany, Kalkulator.Dodaj2(a, b));
}
}
}
Jeśli w Twojej wersji szablonu DataTestMethod/DataRow nie jest dostępne, usuń ten test – reszta w zupełności wystarczy.
Krok E. Uruchom testy
- Menu Test → Uruchom wszystkie testy.
- Otworzy się Test Explorer z wynikiem (zielone = OK). bitedu.pl
5) Jak to „spiąć” z WPF i MAUI – dwa warianty UI
To, co poniżej, to minimalny UI do szybkiego sprawdzenia logiki „na żywo”. Testy i tak robią robotę.
Logika dalej mieszka w Logika/Kalkulator.cs – UI tylko wywołuje metody.
Wariant A: WPF
📄 MainWindow.xaml
<Window x:Class="KalkulatorApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Kalkulator (WPF)" Height="220" Width="360">
<StackPanel Margin="16" VerticalAlignment="Center" Spacing="6">
<TextBlock Text="a:"/>
<TextBox x:Name="txtA" />
<TextBlock Text="b:"/>
<TextBox x:Name="txtB" />
<TextBlock Text="c: (opcjonalnie do operacji na trzech)"/>
<TextBox x:Name="txtC" />
<WrapPanel Margin="0,8,0,0" ItemWidth="150" ItemHeight="32">
<Button Content="Dodaj2 (a+b)" Click="Dodaj2_Click"/>
<Button Content="Dodaj3 (a+b+c)" Click="Dodaj3_Click"/>
<Button Content="Odejmij2 (a-b)" Click="Odejmij2_Click"/>
<Button Content="Odejmij3 (a-b-c)" Click="Odejmij3_Click"/>
</WrapPanel>
<TextBlock x:Name="txtWynik" FontSize="16" FontWeight="Bold" />
</StackPanel>
</Window>
📄 MainWindow.xaml.cs
using System;
using System.Windows;
using KalkulatorApp.Logika;
namespace KalkulatorApp
{
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
int GetInt(string s) => int.TryParse(s, out var v) ? v : 0;
private void Dodaj2_Click(object sender, RoutedEventArgs e)
{
int a = GetInt(txtA.Text), b = GetInt(txtB.Text);
txtWynik.Text = $"Wynik: {Kalkulator.Dodaj2(a, b)}";
}
private void Dodaj3_Click(object sender, RoutedEventArgs e)
{
int a = GetInt(txtA.Text), b = GetInt(txtB.Text), c = GetInt(txtC.Text);
txtWynik.Text = $"Wynik: {Kalkulator.Dodaj3(a, b, c)}";
}
private void Odejmij2_Click(object sender, RoutedEventArgs e)
{
int a = GetInt(txtA.Text), b = GetInt(txtB.Text);
txtWynik.Text = $"Wynik: {Kalkulator.Odejmij2(a, b)}";
}
private void Odejmij3_Click(object sender, RoutedEventArgs e)
{
int a = GetInt(txtA.Text), b = GetInt(txtB.Text), c = GetInt(txtC.Text);
txtWynik.Text = $"Wynik: {Kalkulator.Odejmij3(a, b, c)}";
}
}
}
Wariant B: .NET MAUI
📄 MainPage.xaml
<ContentPage<br> x:Class="KalkulatorApp.MainPage"<br> xmlns="http://schemas.microsoft.com/dotnet/2021/maui"<br> xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"<br> Title="Kalkulator (MAUI)"><br><br> <ScrollView><br> <VerticalStackLayout Padding="20" Spacing="8"><br> <Label Text="a:" /><br> <Entry x:Name="entA" Keyboard="Numeric" /><br> <Label Text="b:" /><br> <Entry x:Name="entB" Keyboard="Numeric" /><br> <Label Text="c: (opcjonalnie)" /><br> <Entry x:Name="entC" Keyboard="Numeric" /><br><br> <HorizontalStackLayout Spacing="8" Margin="0,8,0,0"><br> <Button Text="Dodaj2" Clicked="Dodaj2_Click"/><br> <Button Text="Dodaj3" Clicked="Dodaj3_Click"/><br> </HorizontalStackLayout><br> <HorizontalStackLayout Spacing="8"><br> <Button Text="Odejmij2" Clicked="Odejmij2_Click"/><br> <Button Text="Odejmij3" Clicked="Odejmij3_Click"/><br> </HorizontalStackLayout><br><br> <Label x:Name="lblWynik" FontSize="18" FontAttributes="Bold"/><br> </VerticalStackLayout><br> </ScrollView><br></ContentPage><br>📄 MainPage.xaml.cs
using KalkulatorApp.Logika;
namespace KalkulatorApp
{
public partial class MainPage : ContentPage
{
public MainPage() => InitializeComponent();
int GetInt(string s) => int.TryParse(s, out var v) ? v : 0;
void Dodaj2_Click(object sender, EventArgs e)
{
int a = GetInt(entA.Text), b = GetInt(entB.Text);
lblWynik.Text = $"Wynik: {Kalkulator.Dodaj2(a, b)}";
}
void Dodaj3_Click(object sender, EventArgs e)
{
int a = GetInt(entA.Text), b = GetInt(entB.Text), c = GetInt(entC.Text);
lblWynik.Text = $"Wynik: {Kalkulator.Dodaj3(a, b, c)}";
}
void Odejmij2_Click(object sender, EventArgs e)
{
int a = GetInt(entA.Text), b = GetInt(entB.Text);
lblWynik.Text = $"Wynik: {Kalkulator.Odejmij2(a, b)}";
}
void Odejmij3_Click(object sender, EventArgs e)
{
int a = GetInt(entA.Text), b = GetInt(entB.Text), c = GetInt(entC.Text);
lblWynik.Text = $"Wynik: {Kalkulator.Odejmij3(a, b, c)}";
}
}
}
6) Najważniejsze właściwości i atrybuty testów (MSTest)
[TestClass]– klasa z testami, rozpoznawana przez Test Explorer.[TestMethod]– pojedynczy test.[DataTestMethod]+[DataRow(...)]– (opcjonalnie) jeden test uruchamiany z wieloma zestawami danych.- Asserty (sprawdzacze):
Assert.AreEqual(oczekiwany, wynik)– czy równe,Assert.AreNotEqual,Assert.IsTrue,Assert.IsFalse,Assert.IsNull,Assert.IsNotNull,Assert.Fail()itd. bitedu.pl
7) Podsumowanie – co zapamiętać na INF.04
- Test jednostkowy to mały automat sprawdzający pojedyńczą metodę.
- Trzy kroki AAA: Arrange → Act → Assert.
- W Visual Studio od ręki utworzysz projekt MSTest i uruchomisz testy bez internetu. bitedu.pl
- Oddziel Logika od UI (WPF/MAUI). Testuj Logikę.
- Jeden zestaw testów działa zarówno dla WPF, jak i MAUI, bo testy patrzą na kod w Logika/, a nie na okna.
8) Zadania do samodzielnej pracy
- Dodaj mnożenie i dzielenie
- W
Logika/Kalkulator.csdopiszPomnoz2,Podziel2(zwracaj int; jeśli dzielisz przez 0, zdecyduj: zwróć 0 albo rzuć wyjątek). - Napisz testy MSTest do obu metod, uwzględnij przypadki brzegowe (np. 0, liczby ujemne).
- W
- Dane parametryczne
- Przerób test
Dodaj2_RozneWartosci...tak, by sprawdzał także wartości ujemne i duże liczby (więcej[DataRow]). - Jeśli
[DataTestMethod]nie jest dostępne – napisz 3 osobne[TestMethod].
- Przerób test
- Walidacja wejścia w UI
- Dodaj prostą weryfikację do WPF/MAUI: jeśli pole puste lub nie liczba, pokaż komunikat w Label/TextBlock zamiast liczyć.
- Logika zostaje czysta – walidację robisz w UI albo w oddzielnym helperze w folderze Walidacja.

