Complete Programming Guide for QA/SDET Engineers
Object-Oriented Programming (OOP) organizes code into objects that bundle data and methods together. This is the foundation of test automation frameworks like Page Object Model.
A class is a blueprint or template for creating objects. It defines properties (variables) and behaviors (methods). Think of it as a cookie cutter - the class is the cutter, objects are the cookies.
Key Components:
// Class definition class TestCase { // Instance variables (properties/attributes) String name; String status; int executionTime; // Constructor - called when creating object public TestCase(String name) { this.name = name; this.status = "Not Run"; this.executionTime = 0; } // Methods (behaviors/functions) public void execute() { System.out.println("Executing: " + name); this.status = "Running"; } public void pass() { this.status = "Passed"; System.out.println(name + ": ✓ PASSED"); } public void fail() { this.status = "Failed"; System.out.println(name + ": ✗ FAILED"); } } public class Main { public static void main(String[] args) { // Create objects (instances of the class) TestCase test1 = new TestCase("Login Test"); TestCase test2 = new TestCase("Logout Test"); // Use object methods test1.execute(); test1.pass(); test2.execute(); test2.fail(); } }
Constructors are special methods called when creating objects. They initialize the object's state.
class Browser { String name; String version; boolean headless; // Default constructor (no parameters) public Browser() { this.name = "Chrome"; this.version = "latest"; this.headless = false; } // Parameterized constructor public Browser(String name) { this.name = name; this.version = "latest"; this.headless = false; } // Constructor with all parameters public Browser(String name, String version, boolean headless) { this.name = name; this.version = version; this.headless = headless; } public void launch() { System.out.println("Launching " + name + " " + version); } }
Multiple methods with the same name but different parameters.
class Calculator { public int add(int a, int b) { return a + b; } public double add(double a, double b) { return a + b; } public int add(int a, int b, int c) { return a + b + c; } }
class TestConfig { // Static variables - shared across all instances static String baseUrl = "https://example.com"; static int timeout = 30; static int testCount = 0; String testName; public TestConfig(String testName) { this.testName = testName; testCount++; } // Static method - can be called without object public static void printConfig() { System.out.println("Base URL: " + baseUrl); System.out.println("Tests created: " + testCount); } }
Create a User class with username, email, and a method to display info:
Encapsulation is the practice of hiding internal object details and providing controlled access through public methods (getters/setters). This is a core principle of the Page Object Model in test automation.
Control visibility and access to class members:
| Modifier | Class | Package | Subclass | World |
|---|---|---|---|---|
| public | ✓ | ✓ | ✓ | ✓ |
| protected | ✓ | ✓ | ✓ | ✗ |
| default (no modifier) | ✓ | ✓ | ✗ | ✗ |
| private | ✓ | ✗ | ✗ | ✗ |
class User { // Private variables (encapsulated) private String username; private String password; private int age; public User(String username, String password) { this.username = username; this.password = password; } // Getter methods (read access) public String getUsername() { return username; } public int getAge() { return age; } // Setter methods with validation (controlled write access) public void setAge(int age) { if (age > 0 && age < 150) { this.age = age; } else { System.out.println("Invalid age"); } } // Password verification (not direct access) public boolean verifyPassword(String inputPassword) { return this.password.equals(inputPassword); } }
Create a BankAccount class with private balance and public methods:
Inheritance allows a class to inherit properties and methods from another class, promoting code reuse.
// Parent class (Base class / Superclass) class WebElement { protected String locator; protected String type; public WebElement(String locator, String type) { this.locator = locator; this.type = type; } public void click() { System.out.println("Clicking " + type + ": " + locator); } public void isDisplayed() { System.out.println("Checking if " + type + " is displayed"); } } // Child class (Derived class / Subclass) class Button extends WebElement { public Button(String locator) { super(locator, "Button"); // Call parent constructor } // Additional method specific to Button public void doubleClick() { System.out.println("Double clicking button: " + locator); } } class TextBox extends WebElement { public TextBox(String locator) { super(locator, "TextBox"); } public void enterText(String text) { System.out.println("Entering '" + text + "' in: " + locator); } } public class Main { public static void main(String[] args) { Button btn = new Button("#submit"); btn.click(); // Inherited method btn.doubleClick(); // Own method TextBox input = new TextBox("#username"); input.enterText("admin"); input.isDisplayed(); // Inherited method } }
class TestCase { protected String name; public TestCase(String name) { this.name = name; } public void setUp() { System.out.println("Base setup for: " + name); } public void execute() { System.out.println("Executing test: " + name); } } class WebTest extends TestCase { public WebTest(String name) { super(name); } // Override parent method @Override public void setUp() { super.setUp(); // Call parent method System.out.println("Launching browser..."); } @Override public void execute() { System.out.println("Running web test: " + name); } }
Polymorphism means "many forms" - the ability to process objects differently based on their type.
class Report { public void generate() { System.out.println("Generating basic report"); } } class HTMLReport extends Report { @Override public void generate() { System.out.println("Generating HTML report with styling"); } } class PDFReport extends Report { @Override public void generate() { System.out.println("Generating PDF report"); } } public class Main { public static void main(String[] args) { // Polymorphism - same reference type, different behaviors Report report1 = new Report(); Report report2 = new HTMLReport(); Report report3 = new PDFReport(); report1.generate(); // Basic report report2.generate(); // HTML report report3.generate(); // PDF report } }
class Browser { public void launch() { System.out.println("Launching browser"); } } class ChromeBrowser extends Browser { @Override public void launch() { System.out.println("Starting ChromeDriver"); System.out.println("Launching Chrome browser"); } } class FirefoxBrowser extends Browser { @Override public void launch() { System.out.println("Starting GeckoDriver"); System.out.println("Launching Firefox browser"); } } class TestRunner { public static void runTest(Browser browser) { browser.launch(); // Polymorphic behavior System.out.println("Running test..."); } } public class Main { public static void main(String[] args) { Browser chrome = new ChromeBrowser(); Browser firefox = new FirefoxBrowser(); TestRunner.runTest(chrome); TestRunner.runTest(firefox); } }
Create Shape parent class with Circle and Rectangle children, each calculating area: