Collections in Automation framework

"Where did you use collections in your framework?" is one of the most common Java questions in automation interviews — and a vague answer ("I used List for elements") doesn't score well. This guide shows concrete, realistic uses of List, Set and Map in a Selenium framework, with code you can explain line by line. The pure-Java parts were compiled and run; the outputs are real.

Advertisement

The One-Line Memory Formula

List = many items, in order, duplicates allowed. Set = unique items. Map = look something up by a key.

Need Collection Framework example
Several elements, in page order List<WebElement> findElements() results
Values to compare in order List<String> Checking a sorted product list
Unique IDs Set<String> getWindowHandles(), duplicate checks
Value by name Map<String, String> Config, one row of test data
Many data rows List<Map<String, String>> Excel/CSV/JSON test data
Groups of items Map<String, List<String>> Failures grouped by test class
Shared across parallel threads ConcurrentHashMap Report entries per thread

List — Ordered, Duplicates Allowed

1. Many elements from findElements()

List<WebElement> items = driver.findElements(By.cssSelector(".inventory_item_name"));
Assert.assertEquals(items.size(), 6, "product count");

List<String> names = items.stream().map(WebElement::getText).toList();
Assert.assertTrue(names.contains("Sauce Labs Backpack"));

findElements() returns an empty list when nothing matches, so isEmpty() is also the standard way to check that an element is absent.

2. Verifying sort order ⭐

A classic UI test: after choosing "Price (low to high)", are the prices really sorted?

List<Double> prices = driver.findElements(By.cssSelector(".inventory_item_price")).stream()
        .map(e -> Double.parseDouble(e.getText().replace("$", "")))
        .toList();

List<Double> sorted = new ArrayList<>(prices);
Collections.sort(sorted);
Assert.assertEquals(prices, sorted, "prices are not in ascending order");
// With [499.0, 899.0, 1299.0, 1299.0] → sorted? true

For text, compare against a case-insensitive sort — a plain sort puts capitals first. With ["banana", "Apple", "cherry"] the expected order is [Apple, banana, cherry], so the check correctly reports "not sorted". Copy the list before sorting: sorting the original would make the check always pass.

3. Collecting failures

List<String> brokenLinks = new ArrayList<>();
for (WebElement link : driver.findElements(By.tagName("a"))) {
    String href = link.getDomAttribute("href");
    if (href != null && isBroken(href)) brokenLinks.add(href);
}
Assert.assertTrue(brokenLinks.isEmpty(), "Broken links: " + brokenLinks);

Collecting problems and asserting once at the end reports all failures in one run, instead of stopping at the first.

Set — Unique Values

1. Switching to a new window ⭐

String parent = driver.getWindowHandle();
Set<String> before = driver.getWindowHandles();

driver.findElement(By.linkText("Open terms")).click();
new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.numberOfWindowsToBe(before.size() + 1));

Set<String> newWindows = new HashSet<>(driver.getWindowHandles());
newWindows.removeAll(before);                             // what's left is the new window
driver.switchTo().window(newWindows.iterator().next());
// …
driver.close();
driver.switchTo().window(parent);

getWindowHandles() returns a Set<String> because each handle is unique. Subtracting the "before" set finds the new window reliably — better than looping and hoping the last handle is the new one.

2. Duplicate checks

List<String> ids = List.of("ORD-1", "ORD-2", "ORD-2", "ORD-3");     // order IDs read from a table
Set<String> seen = new HashSet<>();
List<String> duplicates = ids.stream().filter(id -> !seen.add(id)).toList();
// → [ORD-2]

Set.add() returns false for a value already present — a one-line duplicate detector for order numbers, emails or table rows.

Which Set?

Type Order Verified output
HashSet No guaranteed order [Laptop, Watch, Tablet, Camera, Mobile] — not insertion order
LinkedHashSet Insertion order [Mobile, Laptop, Tablet] (duplicate "Mobile" removed)
TreeSet Sorted [Laptop, Mobile, Tablet]

Never write a test that depends on a HashSet's iteration order.

Map — Key-Value Data

1. Configuration

Map<String, String> config = new HashMap<>(Map.of("browser", "chrome", "env", "qa"));
String timeout = config.getOrDefault("timeout", "10");   // "10" — a default instead of null
config.get("timeout");                                   // null — a common source of NullPointerException

Frameworks usually load .properties files (a Properties object is a map) and allow -D system properties to override them — see Maven for Selenium.

2. One row of test data

Map<String, String> user = Map.of("username", "standard_user", "expected", "Products");
login.loginAs(user.get("username"), System.getenv("APP_PASSWORD"));

Using keys instead of positions means reordering columns in the data file doesn't break tests.

List of Maps — Data-Driven Testing ⭐

List<Map<String, String>> rows = ExcelReader.readSheet("/testdata/users.xlsx", "Login");

@DataProvider(name = "users")
public Object[][] users() {
    return rows.stream().map(r -> new Object[]{ r }).toArray(Object[][]::new);
}

@Test(dataProvider = "users")
public void login(Map<String, String> row) { … }
Row (Map) username expected
1 standard_user Products
2 locked_out_user locked out

The List holds the rows; each Map is one row with column names as keys. This is the structure interviewers expect you to recognize. Full reader: Data-Driven Testing With Apache POI.

More Framework Patterns

// Group failures by test class for a summary
Map<String, List<String>> byClass = failed.stream()
        .collect(Collectors.groupingBy(f -> f.split("\\.")[0], TreeMap::new, Collectors.toList()));
// ["LoginTest.valid", "CartTest.add", "LoginTest.locked"]
// → {CartTest=[CartTest.add], LoginTest=[LoginTest.valid, LoginTest.locked]}

// Parallel runs: a plain HashMap can be corrupted by concurrent writes
Map<Long, ExtentTest> testsByThread = new ConcurrentHashMap<>();

// Constants that must not change
List<String> browsers = List.of("chrome", "firefox", "edge");   // immutable — add() throws UnsupportedOperationException

For the driver itself in parallel runs, use ThreadLocal<WebDriver> rather than a map — see Parallel Execution & Grid.

Common Mistakes

  • Relying on HashSet or HashMap order — use LinkedHash- or Tree- versions when order matters.
  • Storing WebElements for later — they go stale after a page refresh; store locators or text instead.
  • Sorting the list you're checking — always compare against a sorted copy.
  • map.get() on a missing key — returns null; use getOrDefault() or validate required keys at startup.
  • Plain HashMap/ArrayList shared across parallel threads — use concurrent collections or per-thread data.

The Interview Answer

"I used List for multiple elements from findElements and for comparing values in order — for example, checking that prices are sorted after applying a filter, by comparing the list with a sorted copy. I used Set for window handles, because they're unique — I subtract the old handles to find the new window — and for duplicate checks. I used Map for configuration and for each row of test data, and a List of Maps as the data structure behind our DataProvider, so each row runs as a separate test. For parallel runs we used ConcurrentHashMap for shared report data and ThreadLocal for the driver." Further reading: Java for Selenium.

Step through these examples line by line — watching the lists, sets and maps fill up — in the Java Code Visualizer.

From Real Projects

Java has been the language of every automation framework I've worked with — Selenium, TestNG, POM classes and Apache POI for Excel data. Interviews for automation roles regularly include basic programs like this one, often followed by a question on OOP concepts. Practice writing it by hand and explaining how you'd test it. On Canolog, the many forms and screens across sales, inventory, finance and service are where keeping page details in POM classes and reusable steps in a business library paid off. Collections show up everywhere in frameworks: lists of elements, maps of test data, sets for uniqueness checks.

📚 Official documentation: Oracle Java Tutorials: Collections · dev.java: Learn Java (Oracle)

FAQs

Where did you use List, Set and Map in your framework?

List for findElements results and ordered comparisons, Set for window handles and duplicate checks, Map for configuration and test data rows, and List for data-driven tests.

Why does getWindowHandles() return a Set?

Each window handle is unique, and there's no meaningful order between windows — a Set models exactly that.

Why is Map used for test data?

Data is naturally named (username, password, expected result); looking values up by key is readable and survives column reordering.

What is List<Map<String, String>>?

A list of rows where each row is a map of column name to value — the usual structure for Excel, CSV or JSON test data.

How do you check that a list shown on screen is sorted?

Read the values into a List, make a sorted copy (case-insensitively for text), and assert the two are equal.

Which collections are safe for parallel test runs?

Concurrent collections such as ConcurrentHashMap for shared data, and ThreadLocal for per-thread objects like the WebDriver.