Commit 259b8eb7 by Patryk Czarnik

Wprowadzenie do testów

parent ac0faaee
package funkcje;
public class Funkcje {
public static long silnia(int n) {
long wynik = 1;
for(int i = 1; i <= n; i++) {
wynik *= i;
}
return wynik;
}
public static long fib(int n) {
if(n <= 1) return n;
return fib(n-2) + fib(n-1);
}
}
package funkcje;
import javax.swing.JOptionPane;
public class Testowanie1_Interaktywnie {
// Jednym ze sposobów, aby przetestować napisane przez nas klasy, metody, funkcje
// jest uruchomić kompletną aplikację, w której tester interaktywnie sprawdza co robi program i jakie wyniki daje.
// Testowanie manualne JEST potrzebne i na pewny etapie musi wystąpić,
// ale stosowanie testownaia manualnego do sprawdzenia czy pojedyncza funkcja działa poprawnie
// jest pracochłonne i kosztowne.
// Wykrycie błędów logicznych, szczególnie obliczeniowych, wymaga dużej uwagi i łatwo takie błędy przeoczyć.
public static void main(String[] args) {
while(true) {
String input = JOptionPane.showInputDialog("Podaj liczbę");
if(input == null) break;
try {
int arg = Integer.parseInt(input);
var silnia = Funkcje.silnia(arg);
var fib = Funkcje.fib(arg);
JOptionPane.showMessageDialog(null,
String.format("silnia(%d) = %d\nfib(%d) = %d",
arg, silnia, arg, fib));
} catch (ArithmeticException | NumberFormatException e) {
JOptionPane.showMessageDialog(null, e, "Błąd", JOptionPane.ERROR_MESSAGE);
}
}
}
}
package funkcje;
public class Testowanie2_Print {
// Jeśli programista, który napisał jakąś funkcję, metodę, klasę ...
// chce tylko sprawdzić czy ta rzecz działa dobrze, może napisać taki prosty programik, który wypisuje coś na ekran.
// I to jest najczęstsze podejście, które jest uważane za złe podejście, przejaw lenistwa itd...
// Napisać i uruchomić jest łatwo, ale:
// - to człowiek sprawdza czy program jest poprawny; NIE MA AUTOMATYCZNEJ ODPOWIEDZI czy jest dobrze czy źle
// - uruchamianie jest jednak bardziej kosztowne niż w testach jednostkowych, bo trzeba spojrzeć na ekran i ocenić czy wyniki / zachowanie są poprawne
public static void main(String[] args) {
var wynik = Funkcje.silnia(5);
System.out.println("silnia(5) = " + wynik);
System.out.println("silnia dla arg 0, 1, 10 : ");
System.out.println(Funkcje.silnia(0));
System.out.println(Funkcje.silnia(1));
System.out.println(Funkcje.silnia(10));
System.out.println();
System.out.println("F(10) = " + Funkcje.fib(10));
}
}
package funkcje;
public class Testowanie3_If {
// Jeśli chcemy, aby program testujący SAM informował, czy testy skończyły się sukcesem, czy porażką,
// można napisać program, który sam w ifach sprawdza wyniki.
// Ten program koncepcyjnie jest już zgodny z ideą testów jednostkowych, chociaż nie używa żadnej biblioteki do testów.
// Patrząc na ten kod aż prosi się o zbudowane pewnego schematu, żeby testy pisać krócej
// i nie robić kopiuj/wklej. Takie schematy istnieją. Najbardziej popularny jest JUnit, inny znany: TestNG.
public static void main(String[] args) {
int ileBledow = 0;
long wynik;
wynik = Funkcje.silnia(0);
if(wynik == 1) {
System.out.println("silnia(0): OK");
} else {
System.out.println("silnia(0): FAIL, zły wynik: " + wynik);
ileBledow++;
}
wynik = Funkcje.silnia(5);
if(wynik == 120) {
System.out.println("silnia(5): OK");
} else {
System.out.println("silnia(5): FAIL, zły wynik: " + wynik);
ileBledow++;
}
wynik = Funkcje.fib(0);
if(wynik == 0) {
System.out.println("fib(0): OK");
} else {
System.out.println("fib(0): FAIL, zły wynik: " + wynik);
ileBledow++;
}
wynik = Funkcje.fib(10);
if(wynik == 55) {
System.out.println("fib(10): OK");
} else {
System.out.println("fib(10): FAIL, zły wynik: " + wynik);
ileBledow++;
}
System.out.println();
if(ileBledow == 0) {
System.out.println("Wszystko OK, nie było błędów");
} else {
System.out.println("Test nie przeszły, było " + ileBledow + " błedów!");
}
}
}
package funkcje;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class Testowanie4_JUnit {
@Test
void testSilnia0() {
// normalnie w testach nie robi się żadnych printów
// tu tylko eksperyment, żeby zobaczyć, że ten kod naprawdę się wykonuje
System.out.println("a kuku");
// W typowym teście wykonujemy scenariusz testowy - tutaj tylko wywołanie funkcji, ale bywają bardziej rozbudowane przykłady
long wynik = Funkcje.silnia(0);
// A pod koniec testu za pomocą asercji sprawdzamy czy kod zadziałał prawidłowo.
// Tutaj sprawdzamy wynik, ale często sprawdza się też stan obiektów itp. rzeczy
// W języku Java istnieje prosta konstrukcja assert:
// assert wynik == 1;
// ale rzadko się jej używa, bo daje marne komunikaty w razie błędu; tylko numer linii
// można podać własny komunikat, ale jest to dużo roboty:
// assert wynik == 1 : "dla silnia 0 wyszedł zły wynik " + wynik;
// Najczęście używa się assertEquals pochodzącej z biblioteki JUnit,
assertEquals(1, wynik);
// albo dedykowanych bibliotek do pisania asercji, np. AssertJ
// Technicznie to działa tak:
// - gdy asercja stwierdza, że warunek jest spełniony (jest OK), to nic się dzieje i test idzie dalej
// - gdy asercja stwierdza, że warunek nie jest spełniony, coś się nie zgadza,
// to wyrzucany jest wyjątek AssertionError i dalsza część testu się nie wykona
// Gdy cały test dojdzie do końca bez wyjątku, to jest sukces.
// Gdy test kończy się wyjątkiem AssertionError - to "failuje"
// Gdy test kończy się innym wyjątkiem (np. NPE) - jest to liczone jako "error"
}
@Test
void testSilnia5() {
long wynik = Funkcje.silnia(5);
assertEquals(120, wynik);
}
@Test
void testFib1() {
long wynik = Funkcje.fib(1);
assertEquals(1, wynik);
}
@Test
void testFib10() {
long wynik = Funkcje.fib(10);
assertEquals(55, wynik);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment