PrzedsprzedażAkademia AI w testach i jakości oprogramowania: 1 350 zł zamiast 1 750 zł netto do 30 listopada

Startuje przedsprzedaż Akademii AI w testach i jakości oprogramowania: 5 tygodni z Tomaszem Stelmachem, start 11 stycznia 2027. Wyjątkowa cena 1 350 zł netto zamiast 1 750 zł tylko do 30 listopada.

zostało 37 dniZobacz program i zapisz się
18. Dziedziczenie w Javie: extends, super, @Override i BasePage
Czas czytania: 14 minut

Dziedziczenie w Javie to mechanizm, w którym jedna klasa przejmuje pola i metody innej klasy przez słowo kluczowe extends, a potem może je rozszerzać albo nadpisywać. Klasa podrzędna jest szczególnym przypadkiem klasy bazowej: tester jest pracownikiem, strona logowania jest stroną.

To osiemnasta lekcja kursu Javy dla testerów. Pod filmem znajdziecie pełną lekcję tekstową: dziedziczenie Java krok po kroku z extends i super, nadpisywanie metod z @Override, różnicę między klasą abstrakcyjną a interfejsem, klasy zapieczętowane (sealed) z Javy 17, zasadę „kompozycja zamiast dziedziczenia” i dwie klasy, które spotkacie w każdym frameworku testów: BaseTest i BasePage. Cały kod skompilowaliśmy poleceniem javac --release 25, a przykłady bez przeglądarki również uruchomiliśmy.

Czym jest dziedziczenie w Javie?

Dziedziczenie to jeden z czterech filarów programowania obiektowego, obok hermetyzacji, abstrakcji i polimorfizmu. Klasa, po której się dziedziczy, to klasa bazowa (nadklasa, rodzic). Klasa, która dziedziczy, to podklasa (klasa pochodna, dziecko). Według specyfikacji języka Java SE 25 (rozdział 8.1.4) każda klasa ma dokładnie jedną bezpośrednią nadklasę, a jeśli jej nie wskażecie, jest nią java.lang.Object. Dlatego każdy obiekt w Javie ma metody toString, equals i hashCode, choć ich nie pisaliście.

Dziedziczenie w Javie, definicja: filar programowania obiektowego, hierarchia klas

Test, który warto sobie zadawać przed każdym extends, to pytanie „czy B jest rodzajem A?”. Tester jest pracownikiem, więc Tester extends Pracownik ma sens. Klient API nie jest loggerem, tylko z loggera korzysta, więc tu dziedziczenie byłoby błędem, o czym więcej w sekcji o kompozycji.

Dziedziczenie w Javie w liczbach

1

bezpośrednia nadklasa każdej klasy, Java nie ma wielodziedziczenia klas

17

wersja Javy, w której klasy sealed weszły na stałe

21

wersja LTS, w której switch po typach sealed jest standardem

450 000+

testów automatycznych napisanych w Quality Island

Źródła: Java Language Specification SE 25, rozdział 8.1.4, 2025; OpenJDK JEP 409, 2021; OpenJDK JEP 441, 2023; dane własne Quality Island 2026.

Dziedziczenie Java w praktyce: extends i super

Podklasę deklarujecie słowem extends, a konstruktor klasy bazowej wywołujecie przez super(...). Do Javy 24 specyfikacja (rozdział 8.8.7) wymagała, żeby wywołanie super było pierwszą instrukcją konstruktora. Od Javy 25, na której prowadzimy kurs, według dokumentu OpenJDK JEP 513 przed super(...) wolno umieścić instrukcje, które nie korzystają z tworzonego obiektu, na przykład walidację argumentów. Przykład jest niżej, pod klasą Tester. Jeśli go nie napiszecie, kompilator sam wstawi super() bez argumentów, co działa tylko wtedy, gdy klasa bazowa ma taki konstruktor.

Pracownik.java, klasa bazowa

public class Pracownik {
    protected final String imie;
    private final int stawkaGodzinowa;

    public Pracownik(String imie, int stawkaGodzinowa) {
        this.imie = imie;
        this.stawkaGodzinowa = stawkaGodzinowa;
    }

    public int wyplata(int godziny) {
        return stawkaGodzinowa * godziny;
    }

    public String przedstawSie() {
        return "Jestem " + imie;
    }
}

Tester.java, podklasa

public class Tester extends Pracownik {
    private final int dodatekZaCertyfikat;

    public Tester(String imie, int stawkaGodzinowa, int dodatekZaCertyfikat) {
        super(imie, stawkaGodzinowa); // najpierw stan klasy bazowej
        this.dodatekZaCertyfikat = dodatekZaCertyfikat;
    }

    @Override
    public int wyplata(int godziny) {
        return super.wyplata(godziny) + dodatekZaCertyfikat;
    }

    @Override
    public String przedstawSie() {
        return super.przedstawSie() + " i testuję oprogramowanie"; // wersja z klasy bazowej plus dopisek
    }
}

Od Javy 25 konstruktor podklasy może sprawdzić argumenty, zanim wywoła super(...). Dzięki temu błędne dane zatrzymacie od razu, bez tworzenia obiektu klasy bazowej:

TesterJep513.java, Java 25 (JEP 513)

public class TesterJep513 extends Pracownik {
    private final int dodatekZaCertyfikat;

    public TesterJep513(String imie, int stawkaGodzinowa, int dodatekZaCertyfikat) {
        if (dodatekZaCertyfikat < 0) { // od Javy 25 wolno przed super(...)
            throw new IllegalArgumentException("Dodatek nie może być ujemny: " + dodatekZaCertyfikat);
        }
        super(imie, stawkaGodzinowa);
        this.dodatekZaCertyfikat = dodatekZaCertyfikat;
    }
}

Skompilowane z --release 25 działa: new TesterJep513("Ola", 100, -1) rzuca IllegalArgumentException. Ten sam plik z --release 21 kończy się błędem flexible constructors is not supported in -source 21, więc w projekcie na starszej Javie walidację przenieście do metody statycznej wywołanej w argumencie super(...). Oba wyniki sprawdziliśmy w JDK 25 11.10.2026.

DziedziczenieDemo.java, wynik w komentarzach

import java.util.List;

public class DziedziczenieDemo {
    public static void main(String[] args) {
        Pracownik anna = new Pracownik("Anna", 100);
        Tester piotr = new Tester("Piotr", 100, 500);

        System.out.println(anna.przedstawSie()); // Jestem Anna
        System.out.println(piotr.przedstawSie()); // Jestem Piotr i testuję oprogramowanie
        System.out.println(piotr.wyplata(160)); // 16500

        // polimorfizm: zmienna typu bazowego, obiekt podklasy
        List<Pracownik> zespol = List.of(anna, piotr);
        int suma = 0;
        for (Pracownik p : zespol) {
            suma += p.wyplata(160); // Java wywoła wersję z klasy obiektu
        }
        System.out.println(suma); // 32500
        System.out.println(piotr instanceof Pracownik); // true
    }
}

Zwróćcie uwagę na trzy rzeczy. Pole imie jest protected, więc podklasa może z niego korzystać, a pole stawkaGodzinowa jest prywatne i Tester sięga po nie tylko przez metodę super.wyplata. Pętla po liście List<Pracownik> wywołuje dla Piotra wersję metody z klasy Tester, bo Java wybiera metodę według klasy obiektu, a nie typu zmiennej. To jest polimorfizm i to dzięki niemu framework testów może trzymać różne strony pod jednym typem BasePage. Szczegóły modyfikatora protected i jego pułapek omawia poprzednia lekcja, 17. Hermetyzacja w Javie, a samo this i kolejność wywołań konstruktorów lekcja 15. Konstruktory.

Jak nadpisać metodę i po co jest @Override?

Nadpisanie (override) to napisanie w podklasie metody o tej samej nazwie i tych samych typach parametrów co w klasie bazowej. Adnotacja @Override nie jest obowiązkowa, ale według dokumentacji API Java SE 25 (wersja z 2025 roku) każe kompilatorowi sprawdzić, czy metoda naprawdę coś nadpisuje. Bez niej literówka w nazwie albo inny typ parametru tworzy po cichu nową metodę, a stara dalej działa.

Pojęcie Co znaczy Przykład
Nadpisanie (override) ta sama sygnatura w podklasie, wybór w czasie działania wyplata(int) w Tester
Przeciążenie (overload) ta sama nazwa, inne parametry, wybór w czasie kompilacji wyplata(int) i wyplata(int, int)
super.metoda() wywołanie wersji z klasy bazowej super.wyplata(godziny) + dodatek
final przy metodzie zakaz nadpisywania metoda bezpieczeństwa, której podklasa nie zmieni
final przy klasie zakaz dziedziczenia String, rekordy

Źródło: Oracle, The Java Tutorials: Overriding and Hiding Methods; Java Language Specification SE 25, 2025, rozdział 8.4.8.

W kodzie testów @Override ratuje przed bardzo podstępnym błędem. Metoda jestOtwarta() w BasePage i przypadkowa jestOtwarte() w podklasie to dwie różne metody. Test woła wersję z klasy bazowej i sprawdza coś innego, niż myślicie. Z adnotacją kompilator zatrzyma Was od razu, co pokazujemy w tabeli błędów niżej.

Klasa abstrakcyjna czy interfejs?

Klasa abstrakcyjna to klasa, z której nie da się utworzyć obiektu i która może mieć metody bez ciała, do uzupełnienia w podklasach. Interfejs opisuje zestaw zachowań, które klasa obiecuje dostarczyć. Klasa może rozszerzać tylko jedną klasę, ale implementować wiele interfejsów, i to zwykle rozstrzyga wybór.

Cecha Klasa abstrakcyjna Interfejs
Ile można użyć naraz jedną (extends) wiele (implements)
Pola ze stanem tak, dowolne nie, tylko stałe static final
Konstruktor tak nie
Metody z ciałem tak tak, default i static od Javy 8, private od Javy 9
Typowe użycie w testach BasePage, BaseTest ze wspólnym stanem Platnosc, MaKoszyk, wspólne zachowanie bez stanu
Pytanie kontrolne czy podklasy dzielą stan i kod? czy różne klasy mają umieć to samo?

Źródło: Oracle, The Java Tutorials: Abstract Methods and Classes; Java Language Specification SE 25, 2025, rozdziały 8.1.1.1 i 9.

Reguła, którą stosujemy w naszych projektach: zaczynajcie od interfejsu, a do klasy abstrakcyjnej sięgajcie dopiero wtedy, gdy kilka klas naprawdę dzieli stan, na przykład obiekt WebDriver i obiekt oczekiwania. Wtedy klasa abstrakcyjna oszczędza powtarzania tych samych pól i konstruktora w każdej stronie.

Czym są klasy zapieczętowane (sealed) z Javy 17?

Klasa albo interfejs zapieczętowany (sealed) sam wskazuje, kto może po nim dziedziczyć, w klauzuli permits. Według dokumentu OpenJDK JEP 409 funkcja weszła na stałe w Javie 17. Według JEP 441 od Javy 21 instrukcja switch potrafi rozpoznać typ obiektu i sprawdzić, że obsłużyliście wszystkie dozwolone podtypy, więc gałąź default nie jest potrzebna.

Platnosci.java, Java 25, wynik w komentarzach

sealed interface Platnosc permits Karta, Blik, Przelew {}

record Karta(String numer) implements Platnosc {}

record Blik(String kod) implements Platnosc {}

record Przelew(String iban) implements Platnosc {}

public class Platnosci {
    static String opis(Platnosc p) {
        // switch bez default: kompilator wie, że innych typów płatności nie ma
        return switch (p) {
            case Karta k -> "karta kończąca się na " + k.numer().substring(k.numer().length() - 4);
            case Blik b -> "BLIK " + b.kod();
            case Przelew pr -> "przelew z " + pr.iban().substring(0, 2);
        };
    }

    public static void main(String[] args) {
        System.out.println(opis(new Karta("4111111111111111"))); // karta kończąca się na 1111
        System.out.println(opis(new Blik("123456")));            // BLIK 123456
        System.out.println(opis(new Przelew("PL61109010140000071219812874"))); // przelew z PL
    }
}

Dla testera to bardzo konkretna korzyść. Gdy programista doda czwartą metodę płatności do permits i zapomni o niej w switch, kod się nie skompiluje. Błąd, który dawniej wychodził w testach albo na produkcji jako nieobsłużony przypadek, wyłapuje kompilator. A Wy dostajecie od razu listę wartości do testów: tyle przypadków, ile typów w permits.

Wbrew pozorom

Najsłynniejszy przykład nadużycia dziedziczenia siedzi w samej bibliotece standardowej. Klasa java.util.Stack z Javy 1.0 dziedziczy po Vector, więc stos pozwala wstawić element do środka metodą add(0, ...), co z definicją stosu nie ma nic wspólnego. Według dokumentacji API Java SE 25 lepiej dziś zamiast niej wybrać interfejs Deque i klasę ArrayDeque. Klasy Stack nie dało się już poprawić, bo kod na całym świecie korzysta z odziedziczonych metod.

StosDemo.java, wynik w komentarzach

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Stack;

public class StosDemo {
    public static void main(String[] args) {
        Stack<String> stos = new Stack<>();
        stos.push("strona 1");
        stos.push("strona 2");
        stos.add(0, "wstawione do środka"); // Stack dziedziczy po Vector, więc to działa
        System.out.println(stos); // [wstawione do środka, strona 1, strona 2]

        Deque<String> historia = new ArrayDeque<>();
        historia.push("strona 1");
        historia.push("strona 2");
        System.out.println(historia.pop()); // strona 2
        // historia.add(0, "...") się nie skompiluje: Deque nie ma wstawiania po indeksie
    }
}

Kiedy kompozycja jest lepsza niż dziedziczenie?

Kompozycja to budowanie klasy z innych obiektów, które trzyma ona w polach, zamiast dziedziczenia po nich. Zasadę „przedkładajcie kompozycję obiektów nad dziedziczenie klas” sformułowała w 1994 roku książka „Design Patterns” Gammy, Helma, Johnsona i Vlissidesa, a Joshua Bloch w „Effective Java” (wydanie 3, 2018, temat 18) pokazuje, jak dziedziczenie po cudzej klasie psuje się przy zmianie jej wnętrza. Test „jest” kontra „ma” rozstrzyga większość przypadków.

Kompozycja.java, wynik w komentarzach

import java.util.ArrayList;
import java.util.List;

class Logger {
    private final List<String> wpisy = new ArrayList<>();

    void zapisz(String wpis) {
        wpisy.add(wpis);
    }

    List<String> wpisy() {
        return List.copyOf(wpisy);
    }
}

class KlientApi {
    private final Logger logger; // KlientApi MA logger, a nie JEST loggerem

    KlientApi(Logger logger) {
        this.logger = logger;
    }

    int pobierzStatus(String sciezka) {
        logger.zapisz("GET " + sciezka);
        return sciezka.startsWith("/api/") ? 200 : 404;
    }
}

public class Kompozycja {
    public static void main(String[] args) {
        Logger logger = new Logger();
        KlientApi klient = new KlientApi(logger);
        System.out.println(klient.pobierzStatus("/api/produkty")); // 200
        System.out.println(klient.pobierzStatus("/brak"));         // 404
        System.out.println(logger.wpisy()); // [GET /api/produkty, GET /brak]
    }
}

KlientApi ma logger w polu i korzysta z niego, ale nie wystawia na zewnątrz metod loggera. Możecie podmienić logger na inny bez ruszania klienta, a w teście podać logger, który zapisuje wpisy do listy, i sprawdzić je asercją. Gdyby KlientApi dziedziczył po Logger, każdy użytkownik klienta mógłby wołać zapisz bezpośrednio, dokładnie jak z wstawianiem do środka stosu.

Zalety dziedziczenia w Javie: reużywalność, mniejsza redundancja, czytelność kodu

Zalety z grafiki, czyli wielokrotne użycie kodu, mniej powtórzeń i czytelniejsza struktura, są prawdziwe, ale mają cenę. Z naszego doświadczenia przy audytach frameworków testów najdroższy w utrzymaniu bywa łańcuch BaseTest, BaseUiTest, BaseLoggedInTest, BaseAdminTest, w którym nikt już nie wie, co dzieje się przed testem. Rozsądny limit to jeden, najwyżej dwa poziomy dziedziczenia, a resztę wspólnego kodu wyciągajcie do klas pomocniczych używanych przez kompozycję. Hierarchia klas głębsza niż drzewo genealogiczne Waszej rodziny to sygnał, że coś poszło nie tak.

Dziedziczenie w testach: BaseTest i BasePage

W automatyzacji testów dziedziczenie spotkacie przede wszystkim w dwóch miejscach. BaseTest zbiera to, co dzieje się przed każdym testem i po nim: start przeglądarki, dane konfiguracyjne, sprzątanie. BasePage zbiera wspólny kod obiektów stron: sterownik, oczekiwania i bezpieczne kliknięcie. Dokumentacja Selenium o wzorcu Page Object opisuje obiekty stron jako jedyne miejsce, które zna strukturę strony, a klasa bazowa pozwala nie powtarzać w nich tego samego kodu.

BasePage.java, Selenium 4

package pl.qi.strony;

import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public abstract class BasePage {
    protected final WebDriver driver;
    private final WebDriverWait wait;

    protected BasePage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    protected WebElement widoczny(By lokator) {
        return wait.until(ExpectedConditions.visibilityOfElementLocated(lokator));
    }

    protected void kliknij(By lokator) {
        wait.until(ExpectedConditions.elementToBeClickable(lokator)).click();
    }

    protected void wpisz(By lokator, String tekst) {
        WebElement pole = widoczny(lokator);
        pole.clear();
        pole.sendKeys(tekst);
    }

    public abstract boolean jestOtwarta();
}

StronaLogowania.java, podklasa BasePage

package pl.qi.strony;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class StronaLogowania extends BasePage {
    private static final By LOGIN = By.id("username");
    private static final By HASLO = By.id("password");
    private static final By ZALOGUJ = By.cssSelector("button[type='submit']");

    public StronaLogowania(WebDriver driver) {
        super(driver);
    }

    public void zalogujJako(String login, String haslo) {
        wpisz(LOGIN, login);
        wpisz(HASLO, haslo);
        kliknij(ZALOGUJ);
    }

    @Override
    public boolean jestOtwarta() {
        return widoczny(LOGIN).isDisplayed();
    }
}

Obie klasy skompilowaliśmy z bibliotekami Selenium 4 (selenium-api i selenium-support). Metoda jestOtwarta jest abstrakcyjna, więc każda nowa strona musi powiedzieć, jak rozpoznać, że się załadowała. Metody pomocnicze są protected: korzystają z nich strony, ale test ich nie widzi i woła tylko czytelne operacje, takie jak zalogujJako.

BaseTest działa podobnie, a JUnit dokłada do tego jedną ważną regułę: metody z adnotacją @BeforeEach z klasy bazowej wykonują się przed metodami @BeforeEach z podklasy, a @AfterEach w odwrotnej kolejności. Sprawdziliśmy to w JUnit 6.1.3 na przykładzie bez przeglądarki, gdzie każdy krok zapisuje się w dzienniku.

BaseTest.java, JUnit 6

import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

abstract class BaseTest {
    protected final List<String> dziennik = new ArrayList<>();

    @BeforeEach
    void przygotujSrodowisko() {
        dziennik.add("BaseTest: start przeglądarki");
    }

    @AfterEach
    void posprzataj() {
        dziennik.add("BaseTest: zamknięcie przeglądarki");
        System.out.println(dziennik);
    }
}

KoszykTest.java, test dziedziczący po BaseTest

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class KoszykTest extends BaseTest {
    @BeforeEach
    void zalogujKlienta() {
        dziennik.add("KoszykTest: logowanie klienta");
    }

    @Test
    void pustyKoszykMaZeroProduktow() {
        dziennik.add("KoszykTest: test");
        assertEquals(3, dziennik.size());
    }
}

Konsola po uruchomieniu, test zakończony sukcesem

[BaseTest: start przeglądarki, KoszykTest: logowanie klienta, KoszykTest: test, BaseTest: zamknięcie przeglądarki]

Jeśli chcecie zobaczyć, jak takie klasy pracują w całym frameworku, przeczytajcie tekst o wzorcach projektowych w automatyzacji testów Selenium WebDriver. Jak rozplanować wdrożenie automatyzacji w firmie, krok po kroku na pół roku, opisuje Strefa QA w planie wdrożenia automatyzacji testów na 6 miesięcy.

Jakie błędy zgłosi kompilator?

Kompilator Javy pilnuje reguł dziedziczenia bardzo dokładnie. Poniżej sześć błędów, które najczęściej widzimy u kursantów, z dosłownym komunikatem javac z JDK 25. Każdy odtworzyliśmy na osobnym pliku.

Błąd w kodzie Komunikat kompilatora Poprawka
podklasa bez super(...), a rodzic nie ma konstruktora bez argumentów constructor Pracownik in class Pracownik cannot be applied to given types; required: String,int found: no arguments wywołajcie w konstruktorze super(imie, stawkaGodzinowa)
@Override przy metodzie z innym typem parametru method does not override or implement a method from a supertype ta sama nazwa i te same typy parametrów co w klasie bazowej
new Raport() dla klasy abstrakcyjnej Raport is abstract; cannot be instantiated utwórzcie obiekt konkretnej podklasy
extends po klasie final cannot inherit from final Konto kompozycja zamiast dziedziczenia
klasa spoza permits implementuje typ sealed class is not allowed to extend sealed class: Platnosc (as it is not listed in its 'permits' clause) dopiszcie klasę do permits albo zmieńcie projekt
class C extends A, B '{' expected jedna nadklasa, a dodatkowe zachowania przez interfejsy

Źródło: komunikaty skopiowane z kompilatora javac (OpenJDK, opcja --release 25), sprawdzone przez Quality Island 11.10.2026.

Ostatni komunikat jest mylący, bo nie mówi wprost „Java nie ma wielodziedziczenia”. Parser po prostu nie spodziewa się przecinka po pierwszej nadklasie. Dobrze o tym wiedzieć, zanim spędzicie kwadrans na szukaniu brakującej klamry.

Ćwiczenie z rozwiązaniem

Zadanie: napiszcie klasę abstrakcyjną Konto z polem saldo, abstrakcyjną metodą limitWyplaty() i metodą wyplac(int kwota), która odrzuca kwoty niedodatnie i większe niż limit. Następnie dwie podklasy: KontoOsobiste, gdzie limit to saldo, i KontoZDebetem, gdzie limit to saldo plus debet. Zanim zajrzycie do rozwiązania, wypiszcie wartości brzegowe, które sprawdzicie.

Cwiczenie.java, rozwiązanie z wynikami

abstract class Konto {
    protected int saldo;

    Konto(int saldo) {
        this.saldo = saldo;
    }

    abstract int limitWyplaty();

    boolean wyplac(int kwota) {
        if (kwota <= 0 || kwota > limitWyplaty()) {
            return false;
        }
        saldo -= kwota;
        return true;
    }
}

class KontoOsobiste extends Konto {
    KontoOsobiste(int saldo) {
        super(saldo);
    }

    @Override
    int limitWyplaty() {
        return saldo;
    }
}

class KontoZDebetem extends Konto {
    private final int debet;

    KontoZDebetem(int saldo, int debet) {
        super(saldo);
        this.debet = debet;
    }

    @Override
    int limitWyplaty() {
        return saldo + debet;
    }
}

public class Cwiczenie {
    public static void main(String[] args) {
        Konto osobiste = new KontoOsobiste(1000);
        Konto zDebetem = new KontoZDebetem(1000, 500);
        System.out.println(osobiste.wyplac(1200)); // false
        System.out.println(zDebetem.wyplac(1200)); // true
        System.out.println(zDebetem.saldo);        // -200
        System.out.println(zDebetem.wyplac(301));  // false, limit to 300
        System.out.println(osobiste.wyplac(0));    // false
    }
}

Na co zwrócić uwagę. Reguła wypłaty mieszka w jednym miejscu, w klasie bazowej, a podklasy dostarczają tylko to, czym się różnią, czyli limit. To wzorzec Template Method w najprostszej postaci. Przypadki testowe w main pokrywają przekroczenie limitu, wypłatę w debecie, przekroczenie o jedną złotówkę po zmianie salda i kwotę zero. Dopiszcie jeszcze wypłatę równą limitowi, która powinna przejść, oraz kwotę ujemną.

Co dalej po tej lekcji

Powtórka

Klasy i obiekty oraz konstruktory: bez nich dziedziczenie nie ma na czym pracować.

Praktyka

Page Object z BasePage na prawdziwej stronie: jedna klasa bazowa, trzy strony, dziesięć testów.

Na szkoleniu

Programowanie obiektowe w Javie z trenerem, z przeglądem Waszego kodu.

Poprzednia lekcja17. HermetyzacjaSpis kursuWszystkie lekcje kursu Javy

To ostatnia z lekcji kursu opublikowanych dotąd na blogu. Jeśli chcecie przećwiczyć dziedziczenie, interfejsy i wzorce obiektowe pod okiem trenera, zobaczcie szkolenie programowanie obiektowe w Javie. Gdy celem są od razu testy, lepszym wyborem będzie programowanie w Javie dla testerów albo szkolenie z automatyzacji testów w Selenium, a gdy potrzebujecie gotowego frameworka z BasePage i BaseTest zbudowanego przez zespół z doświadczeniem, zakres pokazuje strona automatyzacji testów UI. Przez szkolenia Quality Island przeszło już ponad 2 500 specjalistów.

Co zabrać z tego artykułu

01Dziedziczenie w Javie to extends: podklasa przejmuje pola i metody rodzica. Pytanie kontrolne: czy B jest rodzajem A?

02super(…) wywołuje konstruktor klasy bazowej i musi stać w pierwszej linii konstruktora podklasy.

03@Override piszcie zawsze. Bez niej literówka tworzy nową metodę, a test sprawdza nie to, co myślicie.

04Klasa abstrakcyjna, gdy podklasy dzielą stan. Interfejs, gdy różne klasy mają umieć to samo. Sealed, gdy lista podtypów jest zamknięta.

05W testach BaseTest i BasePage, ale najwyżej dwa poziomy. Resztę wspólnego kodu dawajcie przez kompozycję.

Wasz framework testów ma pięć poziomów klas bazowych i nikt nie wie, co dzieje się przed testem? Uporządkujemy go albo zbudujemy od nowa z BasePage i kompozycją.

Zobaczcie zakres i cennik


Powiązane na blogu Quality Island

Pełna lista źródeł

Co o tym sądzisz?

Dodaj komentarz

Bądź na bieżąco
Strefa QA, portal z eksperckimi artykułami o jakości oprogramowania
Bądź na bieżąco
Cyberbezpieczeństwo KSC i NIS2 online: pakiet dla organizacji do 250 osób

11 055,00 zł

Cyberbezpieczeństwo KSC i NIS2 online: pakiet dla organizacji do 50 osób

5 424,00 zł

Cyberbezpieczeństwo KSC i NIS2 online: ścieżka dla zespołów IT

432,00 zł

Popularne artykuły
Język Gherkin: co to jest i jak go używać w testowaniu oprogramowania
Smoke test: co to jest, kiedy go uruchamiać i czym różni się od sanity testu
Jak zostać testerem oprogramowania: ścieżka krok po kroku bez dyplomu informatyka
Najnowsze artykuły
Testowanie migracji danych i systemów: co sprawdzić, zanim przełączycie produkcję
Metryki DORA psują się w erze AI: dlaczego szybkość wydawania przestaje być dowodem jakości
OWASP Top 10:2025 okiem testera: co sprawdzić w każdej z dziesięciu kategorii
Popularne kategorie

Grupa marek jakości oprogramowania

Jakość oprogramowania w Polsce ma swój adres

Quality Island