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 29 dniZobaczcie program i zapiszcie się
14. Programowanie obiektowe: Klasy i Obiekty
Czas czytania: 12 minut

Programowanie obiektowe (OOP, ang. object oriented programming) to sposób budowania programów z obiektów, które łączą dane i operacje na tych danych. Klasa jest szablonem, obiekt to konkretna rzecz zbudowana według tego szablonu. Klasa Uzytkownik mówi, że każdy użytkownik ma e-mail i rolę, a obiekt anna to jeden konkretny użytkownik z adresem anna@example.com.

To czternasta lekcja naszego kursu Javy dla testerów. Dostajecie w niej definicje, które zgadzają się z dokumentacją Oracle, przykłady kodu sprawdzone kompilatorem dla Javy 25 oraz odpowiedź na pytanie, które słyszymy na każdym szkoleniu: po co testerowi klasy i obiekty. Krótka odpowiedź: bez nich nie napiszecie czytelnego frameworka testów, bo wzorzec Page Object to programowanie obiektowe w czystej postaci.

Czym jest programowanie obiektowe?

Programowanie obiektowe organizuje kod wokół obiektów, a nie wokół ciągu instrukcji. Obiekt ma pola (dane, które o sobie wie) i metody (czynności, które potrafi wykonać). Dokumentacja Oracle w samouczku Object-Oriented Programming Concepts opisuje to tak: obiekt przechowuje swój stan w polach i udostępnia zachowanie przez metody.

Java jest językiem obiektowym od pierwszej wersji i wciąż jednym z najpopularniejszych na świecie. Według indeksu TIOBE z września 2026 roku zajmuje 4. miejsce z udziałem 7,54 procent. W automatyzacji testów to nadal częsty wybór, szczególnie w bankach i dużych organizacjach, gdzie backend też jest w Javie. Jeśli zastanawiacie się nad językiem na start, porównujemy opcje w artykule jaki język programowania wybrać do automatyzacji testów.

Klasa a obiekt: jaka jest różnica?

Klasa to definicja: opisuje, jakie pola i metody będą miały obiekty. Obiekt to instancja klasy, czyli konkretny egzemplarz w pamięci, z własnymi wartościami pól. Z jednej klasy tworzycie dowolnie wiele obiektów. Klasa to przepis na sernik, obiekt to sernik. Przepisu nie da się zjeść, za to można z niego upiec dwanaście serników, każdy trochę inny.

Cecha Klasa Obiekt
Czym jest szablon, definicja typu instancja klasy, konkretny egzemplarz
Kiedy powstaje przy pisaniu kodu, kompiluje się do pliku .class w czasie działania programu, przez new
Ile ich jest jedna definicja dowolnie wiele z jednej klasy
Gdzie żyje w kodzie źródłowym w pamięci (na stercie) do czasu usunięcia przez garbage collector
Przykład class Uzytkownik new Uzytkownik("anna@example.com", "admin")

Jak napisać klasę i utworzyć obiekt w Javie?

Poniższą klasę i program skompilowaliśmy poleceniem javac --release 25 i uruchomiliśmy, wynik działania jest w komentarzach. Klasa pilnuje poprawności danych już w konstruktorze, więc obiekt z błędnym e-mailem w ogóle nie powstanie.

Uzytkownik.java, Java 25

public class Uzytkownik {
    private final String email;
    private String rola;
    private boolean aktywny = true;

    public Uzytkownik(String email, String rola) {
        if (email == null || !email.contains("@")) {
            throw new IllegalArgumentException("Niepoprawny e-mail: " + email);
        }
        this.email = email;
        this.rola = rola;
    }

    public void zablokuj() {
        aktywny = false;
    }

    public boolean czyMozeSieZalogowac() {
        return aktywny;
    }

    public String getEmail() {
        return email;
    }

    public String getRola() {
        return rola;
    }
}

Demo.java

public class Demo {
    public static void main(String[] args) {
        Uzytkownik anna = new Uzytkownik("anna@example.com", "admin");
        Uzytkownik piotr = new Uzytkownik("piotr@example.com", "tester");
        Uzytkownik kopiaAnny = new Uzytkownik("anna@example.com", "admin");

        piotr.zablokuj();

        System.out.println(anna.czyMozeSieZalogowac());   // true
        System.out.println(piotr.czyMozeSieZalogowac());  // false
        System.out.println(anna == kopiaAnny);             // false: dwa różne obiekty
    }
}

Trzy rzeczy, na które warto spojrzeć. Pola są private, więc z zewnątrz da się je tylko odczytać przez metody getEmail() i getRola(). Słowo new wywołuje konstruktor i tworzy obiekt, a o konstruktorach piszemy więcej w lekcji 15. Konstruktory. Obiekty anna i kopiaAnny mają identyczne dane, a mimo to == zwraca false, do czego zaraz wrócimy.

Dla obiektów, które tylko przenoszą dane, na przykład danych logowania w teście, Java ma od wersji 16 rekordy. Wprowadził je dokument JEP 395 z 2021 roku. Rekord sam generuje konstruktor, metody dostępu, equals, hashCode i toString:

DaneLogowania.java

public record DaneLogowania(String login, String haslo) {
    public DaneLogowania {
        if (login.isBlank()) {
            throw new IllegalArgumentException("Login nie może być pusty");
        }
    }
}

RecordDemo.java

public class RecordDemo {
    public static void main(String[] args) {
        var a = new DaneLogowania("anna", "Haslo123!");
        var b = new DaneLogowania("anna", "Haslo123!");
        System.out.println(a.equals(b)); // true: rekord porównuje pola
        System.out.println(a == b);      // false: nadal dwa obiekty
    }
}

Stan, zachowanie i tożsamość obiektu

Każdy obiekt ma trzy cechy. Stan to aktualne wartości pól, na przykład aktywny = false po zablokowaniu konta. Zachowanie to metody, które stan odczytują albo zmieniają, na przykład zablokuj(). Tożsamość to fakt, że obiekt jest odrębnym bytem w pamięci, nawet gdy ma takie same dane jak inny.

Stan
Wartości pól w danej chwili. Dwa obiekty tej samej klasy mają zwykle różny stan.
Zachowanie
Metody. Zmieniają stan w kontrolowany sposób, zamiast pozwalać na dowolne przypisania z zewnątrz.
Tożsamość
Operator == porównuje tożsamość (czy to ten sam obiekt), metoda equals porównuje zawartość, jeśli klasa ją zdefiniuje.

W testach różnica między == a equals to klasyczna pułapka. Asercja assertEquals w JUnit używa equals. Jeśli Wasza klasa go nie nadpisuje, dziedziczy wersję z klasy Object, która porównuje tożsamość, i test porównujący dwa „identyczne” obiekty obleje. Rekord rozwiązuje to automatycznie, co widać w przykładzie wyżej. Więcej o asercjach znajdziecie w tekście Asercja: co to jest i jak używać asercji w testach automatycznych.

Wbrew pozorom

Klasa, która nie ma słowa extends, też dziedziczy. Dokumentacja Javy 25 mówi wprost, że klasa Object jest korzeniem hierarchii klas i każda klasa ma ją jako nadklasę. Dlatego nawet pusta klasa class Pusta {} ma metody equals, hashCode i toString. Ten ostatni wypisze coś w rodzaju Pusta@1b6d3586, co w logach z testów wygląda jak szyfr, dopóki ktoś nie nadpisze toString.

Cztery filary programowania obiektowego

Programowanie obiektowe opiera się na czterech filarach. Warto znać je dokładnie, bo w rozmowach rekrutacyjnych na stanowiska automatyzujące padają prawie zawsze, a najczęstsze błędy to mylenie abstrakcji z hermetyzacją i przypisywanie dziedziczenia obiektom zamiast klasom.

Filar Co to jest W Javie Typowy błąd
Hermetyzacja ukrycie wewnętrznego stanu obiektu i dostęp do niego tylko przez metody, które pilnują reguł pola private, metody publiczne, walidacja w konstruktorze publiczne pola i settery bez żadnej kontroli
Abstrakcja pokazanie, co obiekt robi, bez szczegółów, jak to robi; praca na poziomie pojęć, nie implementacji klasy abstract i interfejsy utożsamianie abstrakcji z ukrywaniem danych
Dziedziczenie relacja między klasami: podklasa przejmuje pola i metody nadklasy i może je rozszerzać extends, super; jedna nadklasa mówienie, że obiekt dziedziczy po obiekcie
Polimorfizm ten sam kod wywołuje różne zachowanie zależnie od faktycznej klasy obiektu nadpisywanie metod instancyjnych (@Override), rozstrzygane w czasie działania podawanie metod statycznych jako przykładu nadpisywania

Hermetyzacja

Hermetyzacja chroni obiekt przed wpisaniem do niego bzdur i jest fundamentem, na którym programowanie obiektowe buduje resztę filarów. Klasa Uzytkownik wyżej nie pozwala ustawić e-maila bez znaku @, a stan aktywny zmienia się tylko metodą zablokuj(). Szczegóły z modyfikatorami dostępu są w lekcji 17. Hermetyzacja.

Abstrakcja

Abstrakcja to nie to samo co ukrywanie danych. Hermetyzacja odpowiada na pytanie „kto może zmienić stan”, abstrakcja na pytanie „na jakim poziomie szczegółów o tym myślę”. Klasa abstrakcyjna Powiadomienie poniżej mówi, że każde powiadomienie ma treść i da się je wysłać, ale nie mówi, czy to e-mail, czy SMS. Kod, który wysyła powiadomienia, pracuje na tym pojęciu i nie musi znać szczegółów.

Powiadomienie.java, klasa abstrakcyjna

public abstract class Powiadomienie {
    protected final String odbiorca;

    protected Powiadomienie(String odbiorca) {
        this.odbiorca = odbiorca;
    }

    public abstract String tresc();

    public String wyslij() {
        return "Do: " + odbiorca + " | " + tresc();
    }
}

Dziedziczenie

Dziedziczenie to relacja między klasami, nie między obiektami. Klasa PowiadomienieEmail rozszerza klasę Powiadomienie słowem extends, przejmuje jej pole i metodę wyslij() i dopisuje własną treść. Obiekt podklasy jest jednocześnie instancją nadklasy, ale niczego nie „dziedziczy” od innego obiektu. Więcej przykładów w lekcji 18. Dziedziczenie.

PowiadomienieEmail.java

public class PowiadomienieEmail extends Powiadomienie {
    public PowiadomienieEmail(String odbiorca) {
        super(odbiorca);
    }

    @Override
    public String tresc() {
        return "Twoje zamówienie zostało wysłane (e-mail)";
    }
}

Polimorfizm

Polimorfizm w czasie działania polega na tym, że wywołanie p.wyslij() na liście typu Powiadomienie uruchamia wersję metody z faktycznej klasy obiektu. Program poniżej wypisuje dwie różne wiadomości z jednej pętli:

PowiadomienieSms.java

public class PowiadomienieSms extends Powiadomienie {
    public PowiadomienieSms(String odbiorca) {
        super(odbiorca);
    }

    @Override
    public String tresc() {
        return "Twoje zamówienie zostało wysłane (SMS)";
    }
}

PolimorfizmDemo.java

import java.util.List;

public class PolimorfizmDemo {
    public static void main(String[] args) {
        List<Powiadomienie> kolejka = List.of(
                new PowiadomienieEmail("anna@example.com"),
                new PowiadomienieSms("+48500100200"));

        for (Powiadomienie p : kolejka) {
            System.out.println(p.wyslij()); // ta sama metoda, różne zachowanie
        }
    }
}

Wszystkie cztery klasy skompilowaliśmy razem w JDK 25. Wynik:

Do: anna@example.com | Twoje zamówienie zostało wysłane (e-mail)
Do: +48500100200 | Twoje zamówienie zostało wysłane (SMS)

Przeciążanie metod (kilka metod o tej samej nazwie i różnych parametrach) bywa nazywane polimorfizmem czasu kompilacji. Metody statyczne nie biorą jednak udziału w polimorfizmie: według specyfikacji języka Java (JLS 25, punkt 8.4.8.2) metoda statyczna w podklasie ukrywa metodę nadklasy, a nie ją nadpisuje. Wersję wybiera kompilator na podstawie typu zmiennej, nie obiektu. Widać to w tym przykładzie:

Ukrywanie.java

class Rodzic {
    static String statyczna() { return "Rodzic.statyczna"; }
    String instancyjna() { return "Rodzic.instancyjna"; }
}

class Dziecko extends Rodzic {
    static String statyczna() { return "Dziecko.statyczna"; }   // ukrywa, nie nadpisuje
    @Override
    String instancyjna() { return "Dziecko.instancyjna"; }     // nadpisuje
}

public class Ukrywanie {
    public static void main(String[] args) {
        Rodzic r = new Dziecko();
        System.out.println(r.instancyjna()); // Dziecko.instancyjna
        System.out.println(r.statyczna());   // Rodzic.statyczna
    }
}

Programowanie strukturalne a obiektowe

W programowaniu strukturalnym program to ciąg procedur, które operują na wspólnych danych. Programowanie obiektowe zamyka dane i operacje na nich razem w obiektach. Java pozwala pisać funkcje i pętle, które znacie z lekcji 16. Funkcje, ale zawsze wewnątrz klas. Nawet zwarty plik źródłowy z Javy 25 (JEP 512), w którym metody piszecie bez deklaracji klasy, nie łamie tej zasady: klasę deklaruje za Was kompilator.

Kryterium Strukturalne Obiektowe
Jednostka kodu procedura, funkcja klasa i jej obiekty
Dane często wspólne, przekazywane między funkcjami zamknięte w obiektach, dostęp przez metody
Ponowne użycie kopiowanie i wywoływanie funkcji dziedziczenie, kompozycja, interfejsy
Gdzie się sprawdza krótkie skrypty, obliczenia duże systemy i frameworki testów, które rosną latami

Z tym tematem wiążą się jeszcze dwa pojęcia, o które często pytacie. Kompozycja oznacza, że obiekt składa się z innych obiektów i odpowiada za ich życie: strona logowania ma pola formularza. Agregacja to luźniejsza relacja: obiekt korzysta z innych obiektów, które istnieją niezależnie od niego, jak zespół i jego członkowie. W praktyce frameworków testów kompozycja jest częściej lepszym wyborem niż głębokie dziedziczenie.

Programowanie obiektowe w automatyzacji testów: Page Object

Wzorzec Page Object to najczęstsze miejsce, w którym tester spotyka programowanie obiektowe w codziennej pracy. Dokumentacja Selenium opisuje Page Object jako klasę, która reprezentuje stronę albo jej fragment i ukrywa lokatory przed testami. Testy wołają metody w rodzaju zalogujJako(), a nie szukają elementów po identyfikatorach. Gdy zmieni się układ strony, poprawiacie jedną klasę, a nie sto testów.

Oba fragmenty poniżej skompilowaliśmy z biblioteką selenium-api 4.51.0. Widać w nich trzy filary naraz: abstrakcję (klasa BasePage), dziedziczenie (extends) i hermetyzację (prywatne lokatory).

BasePage.java, Selenium 4

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

public abstract class BasePage {
    protected final WebDriver driver;

    protected BasePage(WebDriver driver) {
        this.driver = driver;
    }

    protected WebElement element(By lokator) {
        return driver.findElement(lokator);
    }

    public abstract boolean czyZaladowana();
}

LoginPage.java

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

public class LoginPage extends BasePage {
    private final By poleEmail = By.id("email");
    private final By poleHaslo = By.id("password");
    private final By przyciskZaloguj = By.cssSelector("[data-testid=login-submit]");

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

    public void zalogujJako(String email, String haslo) {
        element(poleEmail).sendKeys(email);
        element(poleHaslo).sendKeys(haslo);
        element(przyciskZaloguj).click();
    }

    @Override
    public boolean czyZaladowana() {
        return element(przyciskZaloguj).isDisplayed();
    }
}

W naszych projektach automatyzacji ten układ to punkt wyjścia prawie każdego frameworka UI. Przy ponad 450 000 testów automatycznych napisanych w Quality Island (dane własne, 2026) widzimy też odwrotną stronę: hierarchie z pięcioma poziomami dziedziczenia stron, w których nikt nie wie, skąd bierze się metoda. Dlatego radzimy jedną bazową klasę i komponenty składane przez kompozycję. Więcej wzorców opisujemy w tekście Automatyzacja testów Selenium WebDriver: wzorce projektowe, a jeśli chcecie, żeby taki framework zbudował dla Was zespół z doświadczeniem, zobaczcie automatyzację testów UI.

Najczęstsze błędy początkujących

Z naszego doświadczenia ze szkoleń, przez które przeszło ponad 2 500 specjalistów, te pięć błędów wraca najczęściej. Każdy ma prostą poprawkę:

  1. Publiczne pola. Każdy test może wpisać do obiektu cokolwiek. Poprawka: private i walidacja w konstruktorze.
  2. Porównywanie obiektów przez ==. Test obleje mimo identycznych danych. Poprawka: equals albo rekord.
  3. Dziedziczenie dla wygody. Klasa testowa dziedziczy po klasie z narzędziami tylko po to, żeby mieć dostęp do metod. Poprawka: kompozycja albo klasa pomocnicza.
  4. Klasy „Boga”. Jedna klasa Utils na 2 000 linii. Poprawka: jedna odpowiedzialność na klasę.
  5. Mylenie abstrakcji z hermetyzacją na rozmowie rekrutacyjnej. Poprawka: zapamiętajcie pytania „co robi” (abstrakcja) i „kto może zmienić stan” (hermetyzacja).

Jeśli wolicie przećwiczyć to z trenerem na żywym kodzie, mamy szkolenia Programowanie obiektowe w Java i Programowanie w języku Java dla testerów oprogramowania. Prowadzą je praktycy z co najmniej 5 latami doświadczenia w projektach. Jeśli szukacie pierwszej pracy w automatyzacji, profile kompetencyjne testerów publikuje QA Board, platforma łącząca specjalistów QA z firmami.

Co zabrać z tego artykułu

01Klasa to szablon, obiekt to jego instancja w pamięci. Z jednej klasy powstaje dowolnie wiele obiektów.

02Obiekt ma stan (pola), zachowanie (metody) i tożsamość. == porównuje tożsamość, equals zawartość.

03Abstrakcja to praca na pojęciu „co robi”, hermetyzacja to kontrola nad tym, kto zmienia stan. To dwa różne filary.

04Dziedziczenie łączy klasy, nie obiekty. Polimorfizm działa na metodach instancyjnych; metody statyczne są ukrywane, nie nadpisywane.

05Page Object w Selenium to programowanie obiektowe w praktyce testera: jedna klasa na stronę, lokatory prywatne.

Źródło: Oracle Java Tutorials, JLS Java SE 25, dokumentacja Selenium, JEP 395, TIOBE 09.2026, kod sprawdzony kompilatorem JDK 25 11.10.2026.

Budujecie framework testów w Javie i chcecie, żeby przetrwał kolejne wydania? Pomożemy zaprojektować strukturę klas i przenieść testy na Page Object.

Zapytaj o automatyzację

Poprzednia lekcja13. TabliceSpis kursuWszystkie lekcje kursu JavyNastępna lekcja15. Konstruktory

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: zarząd, pracownicy, zespoły IT i pakiety dla organizacji

od 199,00 zł netto

Kompetencje cyfrowe i AI dla pracowników 50+
Kompetencje cyfrowe i AI dla pracowników 50+: szkolenie praktyczne

1 000,00 zł

07.12.26, 18.01.27, 15.02.27, 15.03.27, 19.04.27
1 dzień
Europejski Akt o Dostępności w praktyce
Europejski Akt o Dostępności w praktyce: wymagania ustawy dla e-commerce, banków i usług cyfrowych

1 290,00 zł

01.12.26, 19.01.27, 16.02.27, 16.03.27, 20.04.27
1 dzień
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
AI w testowaniu oprogramowania: szablon promptu, tabela decyzyjna i liczby z badań
Wdrożenie AI w zespole QA: plan 90 dni, koszt pilotażu i karta mierników
NIS2 a dostawcy oprogramowania: jakich testów zażąda od Was klient objęty KSC
Popularne kategorie

Grupa marek jakości oprogramowania

Jakość oprogramowania w Polsce ma swój adres

Quality Island