assert_
glossary ↓ downloads
track: java · selenium
suite 02 · java foundations

Intro to OOP — why frameworks look the way they do

Java foundations14 min
as a manual tester

You organize test cases into modules: 'Login suite', 'Checkout suite' — each owning its steps and data.

in automation

Classes are that organization for code: each class bundles related data and behavior. A LoginPage class owns everything about the login page.

Object-oriented programming sounds abstract until you see what it's for: putting related data and methods in one named place. You need just four ideas to read and write real framework code.

1. A class is a blueprint; an object is one instance of it

TestUser.java
public class TestUser {
    // fields — the data every TestUser has
    String username;
    String role;

    // constructor — how you make one
    public TestUser(String username, String role) {
        this.username = username;
        this.role = role;
    }

    // method — behavior that uses the data
    public boolean isAdmin() {
        return role.equals("admin");
    }
}

// creating objects (instances) from the blueprint:
TestUser alice = new TestUser("alice.qa", "admin");
TestUser bob   = new TestUser("bob.qa",   "viewer");
System.out.println(alice.isAdmin());  // true
predict: what does this print? think it through, then reveal
output
true

You've already used objects constantly: String is a class, and email.contains("@") calls a method on a String object. new ChromeDriver() in Suite 04 creates a driver object. The dot means "ask this object to do something."

2. Encapsulation — hide the messy details

A class exposes clean methods and hides how they work. Callers of login(user, pass) shouldn't know or care which locators it uses inside. When the page changes, the inside changes; the outside stays stable. This principle is the entire Page Object Model, one lesson early:

LoginPage.java — a preview of Suite 04
public class LoginPage {
    // hidden inside: locators, waits, the messy details

    public void login(String user, String pass) { /* ... */ }
    public String getErrorMessage() { /* ... */ return ""; }
}

// the test reads like a test case, not like plumbing:
LoginPage loginPage = new LoginPage();
loginPage.login("wrong", "credentials");
// assert on loginPage.getErrorMessage() ...

3 & 4. Inheritance and interfaces — recognize, don't master

Inheritance (class LoginTest extends BaseTest) lets a class reuse another's members — frameworks use a BaseTest for shared setup like starting the browser. An interface is a contract of methods with no implementation — WebDriver itself is one, which is why the same test runs on Chrome or Firefox. For now you only need to recognize these when you see them.

⚡ exercise · design a CartPage class

On paper, sketch a CartPage class: 2 fields it might hold, a constructor, and 3 methods — at least one action (void) and one question (returns a value). Reuse your method signatures from the Methods lesson if you like.

show a solution
public class CartPage {
    WebDriver driver;
    String url = "https://shop.example.com/cart";

    public CartPage(WebDriver driver) { this.driver = driver; }

    public void    removeItem(String name) { /* ... */ }
    public void    applyDiscount(String code) { /* ... */ }
    public double  getTotal() { /* ... */ return 0; }
}
key takeaways
  • Class = blueprint, object = instance, dot = ask the object to act.
  • Encapsulation hides page plumbing behind clean methods — that IS the Page Object Model.
  • Inheritance shares setup (BaseTest); interfaces are contracts (WebDriver is one).
  • You now know enough OOP to read real framework code.
← Collections — test data in bulk Suite test →