Skip to content

Barclays β€” SDET / Automation Engineer β€” 3-Round Interview Q&A

How to use this file: Read the answer, then say it out loud in your own words. Each answer is written in simple English with a small example so it sticks. Code is Java/Selenium/TestNG + RestAssured (your Avysh B2B and RestAssured_API stacks) so you can speak from real experience.

Barclays is a bank (BFSI). Wherever you can, give a banking example β€” money transfer, login, statements, payments. It shows you fit their world.

⚠️ The behavioural answers (Round 3) use placeholder stories. Swap in your real numbers and project names before the interview.


Round 1 β€” Core Java & Selenium

1. Difference between findElement() and findElements()

One line: findElement returns one element; findElements returns a list of all matches.

findElement() findElements()
Returns A single WebElement A List<WebElement>
If nothing found Throws NoSuchElementException Returns an empty list (no error)
Use it for The login button, a single field Counting rows, all search results

Example (banking): On a "Transactions" page you want to check how many rows showed up:

List<WebElement> rows = driver.findElements(By.cssSelector("table#txns tr"));
System.out.println("Transactions found: " + rows.size());
Memory hook: the s in findElement**s** = several, and "several" can be zero (empty list, no crash). That empty-list behaviour is the favourite trick: use findElements(...).size() == 0 to check an element is absent.


2. How do you handle dynamic web elements?

"Dynamic" = the element's id/text/position changes each time (e.g. id="btn_8f3a" today, id="btn_92kk" tomorrow), or it appears after a delay (AJAX).

My approach, in order: 1. Write a stable locator β€” don't depend on the changing part. Use XPath/CSS that matches the part that stays the same: - //button[contains(@id,'btn_')] β€” matches any id starting with btn_ - //label[text()='Amount']/following-sibling::input β€” locate by the stable label, not the input's own id - starts-with(), contains(), following-sibling, ancestor are my main tools. 2. Wait for it properly β€” use explicit waits (WebDriverWait) so I wait until it's clickable/visible, not a fixed Thread.sleep. 3. Anchor to a stable parent β€” find a stable container first, then search inside it.

Example: a "Pay Now" button whose id changes but text doesn't:

WebElement pay = wait.until(ExpectedConditions.elementToBeClickable(
        By.xpath("//button[normalize-space()='Pay Now']")));
pay.click();
Memory hook: "Locate by what's stable (text/label), wait for what's slow (AJAX)."


3. Types of waits in Selenium

There are three, and mixing them up is a common mistake:

  1. Implicit wait β€” a global "be patient for up to N seconds for any element" setting. Set once.

    driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
    
    Like telling the whole team "wait up to 10 min for anyone who's late."

  2. Explicit wait β€” wait for one specific condition on one element. Most powerful and recommended.

    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("balance")));
    
    Like waiting at the door specifically until Rohan arrives.

  3. Fluent wait β€” an explicit wait with extras: you set the polling interval (how often to check) and which exceptions to ignore.

    Wait<WebDriver> fluent = new FluentWait<>(driver)
         .withTimeout(Duration.ofSeconds(20))
         .pollingEvery(Duration.ofSeconds(2))
         .ignoring(NoSuchElementException.class);
    

Golden rule I follow: never mix implicit + explicit waits (they can add up unpredictably). I keep implicit at 0 and use explicit waits everywhere. And I never use Thread.sleep in real tests β€” it always either wastes time or is too short.

Memory hook: Implicit = everyone, Explicit = one element/condition, Fluent = explicit + polling.


4. XPath vs CSS Selector

Both are ways to point at an element. Differences:

CSS Selector XPath
Speed Slightly faster Slightly slower
Direction Forward only (parent β†’ child) Both ways (can go to parent/ancestor)
Text matching ❌ Can't select by visible text βœ… Can: //*[text()='Login']
Readability Shorter, cleaner More powerful but wordier

Examples: - CSS: input#username , .btn-primary , div.card > input - XPath: //input[@id='username'] , //label[text()='Email']/following-sibling::input

When I pick which: CSS for normal cases (faster, cleaner). XPath when I must match by text or walk up to a parent/sibling β€” which CSS simply can't do.

Memory hook: "CSS is faster, XPath is smarter (text + go-up)."


5. Handling multiple windows / tabs

When you click something that opens a new tab (e.g. "Terms & Conditions"), Selenium still looks at the old tab until you tell it to switch. Each window has a unique window handle (an id string).

String mainWindow = driver.getWindowHandle();          // remember the main one
// click the link that opens a new tab ...
for (String handle : driver.getWindowHandles()) {       // all open windows
    if (!handle.equals(mainWindow)) {
        driver.switchTo().window(handle);               // jump to the new one
    }
}
// do work in the new tab ...
driver.close();                                         // close just this tab
driver.switchTo().window(mainWindow);                   // go back to main
Key point: getWindowHandle() (singular) = current window; getWindowHandles() (plural, a Set) = all of them. driver.close() closes the current tab; driver.quit() closes everything.

Memory hook: "Save main β†’ loop handles β†’ switch β†’ work β†’ close β†’ switch back."


6. How do you design a Page Object Model (POM) framework?

Idea in one line: each web page becomes one Java class. That class holds the page's locators and actions. The test only calls those actions β€” it never sees raw locators.

Why: if the UI changes, you fix it in one place (the page class), not in 50 tests. Clean, reusable, easy to read.

Structure:

BasePage         -> common stuff (driver, waits, click(), type())
LoginPage        -> locators + login() method
AccountsPage     -> locators + getBalance(), openTransfer()
BaseTest         -> setup()/teardown() (open & close browser)
LoginTest        -> the actual test, reads like English

Example page class:

public class LoginPage extends BasePage {
    private By username = By.id("user");
    private By password = By.id("pass");
    private By loginBtn = By.id("login");

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

    public AccountsPage login(String user, String pass) {
        type(username, user);
        type(password, pass);
        click(loginBtn);
        return new AccountsPage(driver);   // return the next page
    }
}
The test then reads like a sentence:
new LoginPage(driver).login("rohan", "Pass@123");
Page Factory: an optional Selenium helper that uses @FindBy annotations + initElements() to wire locators. I know it but prefer plain By locators β€” they're clearer and don't have stale-element surprises.

Memory hook: "One page = one class. Tests speak business, pages keep the locators."


7. final, static, and this in Java

  • final = "cannot change."
  • final variable β†’ a constant: final String URL = "https://bank.com";
  • final method β†’ can't be overridden by a child class.
  • final class β†’ can't be extended (e.g. String is final).
  • Example: I make config values final so no test accidentally changes the base URL.
  • static = "belongs to the class, not to one object." Shared by all, no need to create an object.
  • static method β†’ call it as Utils.readConfig(). Utility/helper methods are usually static.
  • Example: WaitUtils.waitForVisible(...) β€” a static helper used everywhere.
  • this = "the current object." Used to tell apart a field from a parameter with the same name.
    public Account(String name) { this.name = name; }  // this.name = field, name = parameter
    

Memory hook: final = can't change Β· static = shared by the class Β· this = me, this object.


8. Collection Framework β€” where you used HashMap / ArrayList

The Collections framework is Java's set of ready-made containers: List, Set, Map.

  • ArrayList β€” an ordered list, allows duplicates, access by index. Where I used it: storing all rows from a results table, then looping to verify.
    List<String> accountNames = new ArrayList<>();
    for (WebElement row : rows) accountNames.add(row.getText());
    
  • HashMap β€” key β†’ value pairs, super fast lookup. Where I used it: holding test data / expected results, or building a request body.
    Map<String, String> testData = new HashMap<>();
    testData.put("amount", "500");
    testData.put("toAccount", "1234");          // later: testData.get("amount")
    
  • HashSet β€” unique values only. Where I used it: checking there are no duplicate transaction IDs.
    Set<String> ids = new HashSet<>(allTxnIds);
    Assert.assertEquals(ids.size(), allTxnIds.size(), "Duplicate transaction id found!");
    

Quick differences to remember: - List = ordered + duplicates OK. Set = no duplicates. Map = key/value. - ArrayList is fast to read by index; LinkedList is faster for lots of insert/delete. - HashMap is unordered; LinkedHashMap keeps insertion order; TreeMap keeps sorted order.

Memory hook: List = a queue of people (duplicates fine), Set = a guest list (no repeats), Map = a phone book (name β†’ number).


9. How do you handle exceptions in Selenium scripts?

Common Selenium exceptions and how I handle each:

Exception Why it happens Fix
NoSuchElementException Locator wrong, or element not loaded yet Fix locator / add explicit wait
StaleElementReferenceException The element was re-rendered, your reference is old Re-find the element (locate again)
TimeoutException Explicit wait expired Increase timeout / check the condition
ElementClickInterceptedException A popup/overlay is on top Wait for overlay to close, or scroll into view

How I structure it: - Use try/catch only where I can actually recover or want a clearer message β€” not to hide failures. - Use explicit waits to prevent most timing exceptions in the first place. - Add a TestNG listener / @AfterMethod that takes a screenshot on failure so I can see what the page looked like.

try {
    wait.until(ExpectedConditions.elementToBeClickable(payBtn)).click();
} catch (TimeoutException e) {
    Assert.fail("Pay button never became clickable: " + e.getMessage());
}
Principle: catch to add information or recover β€” never to silently swallow a real failure.


10. Data-driven testing with TestNG or Excel

Idea: run the same test with many sets of data (e.g. test login with 10 different username/password combos) without copying the test 10 times.

Way 1 β€” TestNG @DataProvider (data lives in code):

@DataProvider(name = "loginData")
public Object[][] loginData() {
    return new Object[][] {
        {"validUser", "Pass@123", true},
        {"validUser", "wrong",     false},
        {"",          "Pass@123", false}
    };
}

@Test(dataProvider = "loginData")
public void testLogin(String user, String pass, boolean shouldPass) {
    boolean result = new LoginPage(driver).login(user, pass).isLoggedIn();
    Assert.assertEquals(result, shouldPass);
}
TestNG runs the test once per row automatically.

Way 2 β€” Excel (Apache POI) (data lives in a spreadsheet so non-coders can edit it): - Read rows with Apache POI into an Object[][], then feed it to the @DataProvider. - Good when business/manual testers maintain the data.

Other options I mention: @Parameters from testng.xml for a few values (like browser name), JSON/CSV files, or a database for big data sets.

Memory hook: "One test, many rows. DataProvider = data in code, Excel/POI = data in a sheet."


Round 2 β€” Framework & Advanced Concepts

1. Walk me through your automation framework architecture

Keep this as a clear, layered story (banking flavour from the Avysh B2B / RestAssured work):

"It's a Maven-based hybrid framework (Page Object Model + data-driven), using Java, Selenium, TestNG and RestAssured. It has clear layers: - Tests layer β€” TestNG test classes, grouped as smoke/regression. They read like business steps. - Page Objects layer β€” one class per page, with locators + actions, all extending a BasePage. - API layer β€” RestAssured service classes + request/response POJOs + JSON-schema validators, so I can set up data or verify via API. - Core/utils layer β€” DriverFactory (thread-safe with ThreadLocal for parallel runs), WaitUtils, ConfigReader, Excel/JSON data readers, screenshot util. - Config layer β€” .properties files per environment (QA/dev/pre-prod) chosen by a Maven profile or system property. - Reporting β€” Extent/Allure reports, plus screenshots on failure attached automatically. - CI β€” runs on Jenkins/GitHub Actions, triggered on each push, results published as reports."

Then offer the flow: Jenkins β†’ Maven β†’ TestNG suite β†’ DriverFactory opens browser β†’ tests call Page Objects β†’ assertions β†’ listeners capture screenshots β†’ report published.

Memory hook β€” name the layers top to bottom: Tests β†’ Pages β†’ API β†’ Utils β†’ Config β†’ Reports β†’ CI.


2. Managing test data and environment configuration

Environments: I keep a separate properties file per environment (qa.properties, dev.properties, preprod.properties) holding base URL, credentials, API endpoints. The active one is picked at runtime:

mvn test -Denv=qa
A ConfigReader loads the right file. No URLs or passwords are hard-coded in tests.

Test data: depends on the need β€” - Static data (rarely changes) β†’ JSON/Excel files. - Dynamic data (must be fresh each run, e.g. a new user) β†’ I create it via API in setup, then use it in the UI test, then clean it up after. This avoids tests stepping on each other. - Secrets (passwords, API keys) β†’ environment variables / a vault / CI secrets, never committed to Git.

Memory hook: "Config per environment, data created fresh via API, secrets out of the repo."


3. Best practices to make scripts maintainable

My checklist: 1. POM β€” locators in one place, so UI changes = one fix. 2. No hard-coded waits (Thread.sleep) β€” explicit waits only. 3. No hard-coded data/URLs β€” externalise to config/data files. 4. Reusable utilities β€” common actions (click, type, wait, read Excel) written once. 5. Independent tests β€” each test sets up its own data and can run alone, in any order. 6. Clear naming β€” transferMoney_failsWhenAmountExceedsLimit() tells you what it does. 7. Small methods, single responsibility β€” easier to read and fix. 8. Version control + code review β€” everything in Git, reviewed via pull requests.

Memory hook: "One place for locators, no magic numbers, independent tests, reusable utils."


4. Handling failed test cases in Jenkins / CI-CD

  1. See it fast β€” Jenkins shows pass/fail; I publish the Extent/Allure report and failure screenshots as build artifacts so I can look without re-running.
  2. Is it a real bug or a flaky test? I check the screenshot + logs. Real bug β†’ raise a defect with the report attached. Flaky/environment issue β†’ fix the test or the environment.
  3. TestNG testng-failed.xml β€” TestNG auto-generates a file listing only the failed tests, so I can re-run just those instead of the whole suite.
  4. Retry β€” a TestNG IRetryAnalyzer retries a failed test once or twice to filter out genuine flakiness (but I track retries so flakiness doesn't get hidden forever).
  5. Notify β€” Jenkins emails / Slack message to the team on failure.

Memory hook: "Screenshot + report β†’ bug or flaky? β†’ re-run failed only β†’ notify team."


5. Strategy for flaky tests

A flaky test passes sometimes and fails other times without any code change. They destroy trust in automation, so I take them seriously.

Common causes & my fixes: | Cause | Fix | |---|---| | Timing (element not ready) | Replace Thread.sleep with explicit waits | | Test depends on another test's data | Make each test independent, create its own data | | Shared/changing test data | Use fresh data per run, clean up after | | Environment slowness | Stable test environment, sensible timeouts | | Animations / overlays | Wait for overlay to disappear before clicking |

Process: I quarantine a known-flaky test (tag it, keep it out of the gate), add retry-with-logging to measure how often it flaps, then find the root cause and fix it β€” retry is a band-aid, not a cure. I never just "re-run until green."

Memory hook: "Flaky = timing or data. Fix the root cause; retry only to measure, not to hide."


6. How do you decide which test cases to automate?

I automate the ones that give the best return. Good candidates: - Repetitive tests run every release (regression, smoke). - High-risk / high-value flows β€” for a bank: login, fund transfer, payments, balance (a bug here is critical). - Data-driven tests (same steps, many inputs). - Stable features (UI not changing every week). - Tests that are hard or slow to do by hand (e.g. across many browsers).

I usually don't automate: - One-time tests, or features still changing fast. - Tests needing human judgement (look-and-feel, usability). - Very complex setups where automation cost > the value.

Memory hook: "Automate the boring, risky, and repeated. Leave the one-off and the eye-judgement to humans."


7. Git branching strategy / version control workflow

I keep it simple and team-friendly: - main β€” always stable/releasable. - develop (or directly feature branches) β€” integration. - feature/... branches β€” one per task, e.g. feature/transfer-tests. - Work β†’ commit small, clear messages β†’ push β†’ open a Pull Request β†’ code review β†’ CI runs the tests β†’ merge. - Never commit straight to main. Pull latest before starting to avoid conflicts.

I mention I've used feature-branch / GitFlow-style workflows, with PR reviews and CI checks before merge.

Memory hook: "Branch per feature β†’ PR β†’ review + CI β†’ merge. main stays clean."


8. Integrating API testing in the framework

Why mix API + UI: APIs are faster and more stable than UI. I use them two ways: 1. As a tool for UI tests β€” set up data (create a user/account) and clean up via API, so UI tests start in a known state quickly. 2. As tests themselves β€” validate the backend directly with RestAssured: status code, response body, JSON schema, headers, response time.

Example (RestAssured):

given()
    .header("Authorization", "Bearer " + token)
    .contentType(ContentType.JSON)
    .body(requestPayload)
.when()
    .post("/accounts/transfer")
.then()
    .statusCode(200)
    .body("status", equalTo("SUCCESS"))
    .body(matchesJsonSchemaInClasspath("transfer-schema.json"));   // schema check
In my framework these live in a service/API layer with reusable request builders and JSON-schema validators (like my RestAssured framework with ~60 tests and schema validation across API versions).

Memory hook: "API for fast setup + direct checks; UI for the real user journey."


9. Common automation challenges and how you resolved them

Pick 2–3 and tell them as mini-stories:

  1. Flaky tests from timing β†’ root cause was Thread.sleep and AJAX. Fix: replaced with explicit waits β†’ pass rate went from ~80% to ~98%.
  2. Dynamic locators (ids changing every build) β†’ switched to stable XPath/CSS using contains() and label-anchored locators.
  3. Slow regression suite (took too long) β†’ added parallel execution (TestNG parallel, thread-safe ThreadLocal driver) β†’ cut run time roughly in half.
  4. Test data collisions (tests sharing one account) β†’ moved to fresh data per run via API + cleanup, so tests stopped interfering.

Memory hook: Challenge β†’ root cause β†’ fix β†’ measurable result. Always end with the result.


10. Parallel execution / cross-browser testing

Parallel execution = run many tests at the same time to save time. - TestNG: <suite parallel="methods" thread-count="4">. - The driver must be thread-safe β€” I use ThreadLocal<WebDriver> in DriverFactory so each thread gets its own browser (otherwise threads fight over one browser).

Cross-browser = run the same tests on Chrome, Firefox, Edge. - Browser chosen by a parameter (@Parameters("browser") or -Dbrowser=chrome), and DriverFactory returns the right driver. - For many browser/OS combos I use a cloud grid like Selenium Grid or BrowserStack/Sauce Labs instead of maintaining machines myself.

Example flow: testng.xml defines 3 <test> blocks (Chrome/Firefox/Edge), run in parallel, each picks its browser via parameter.

Memory hook: "Parallel saves time (need ThreadLocal driver); cross-browser = same test, many browsers, often on a cloud grid."


Round 3 β€” Managerial + HR

These are STAR answers: Situation β†’ Task β†’ Action β†’ Result. Keep them ~60–90 seconds. Replace the placeholders with your real projects/numbers.

1. A time you found a critical bug through automation

Situation: On the Avysh B2B platform, we had a nightly automated regression + API suite. One morning a normally-green test failed. Task: I had to find out if it was a real defect or a flaky test before the release that day. Action: My RestAssured schema-validation test caught that a field in the order-response had quietly changed type β€” a number had become a string after a backend change. The screenshot and API logs in the report confirmed the UI then showed a wrong total. I reproduced it, raised a priority defect with the report attached, and flagged the release risk. Result: We caught it before production. Because the check was automated and ran nightly, we found it within hours instead of a customer finding a wrong amount. We also added an extra contract test so that type of change would fail loudly in future.

Why it lands for a bank: it's about money accuracy + catching it early + preventing recurrence.


2. How do you ensure test coverage and quality metrics?

Coverage β€” I look at it from a few angles: - Requirement coverage β€” a traceability matrix mapping each requirement/user story to its test cases, so nothing is missed. - Risk-based β€” make sure the critical flows (login, transfer, payment) are deeply covered, not just easy paths. - Test-type coverage β€” unit (dev), API, UI, plus negative & boundary cases.

Metrics I track and report: - Pass/fail rate and trend over builds. - Automation coverage % (how much of regression is automated). - Defect leakage (bugs that escaped to production β€” the real quality signal). - Flaky-test rate and suite execution time. - Defect density by module.

Point I make: numbers are a means, not the goal β€” high pass-rate with high defect leakage means the tests aren't testing the right things. I watch leakage closely.

Memory hook: "Trace requirements β†’ cover the risky flows β†’ measure pass-rate, coverage, and especially defect leakage."


3. A challenging situation with developers or deadlines, and how you handled it

Situation: Close to a release, a developer felt a bug I raised was "not really a bug," and the deadline was tight. Task: Get the issue fixed without it turning into a personal conflict or blocking the release unnecessarily. Action: I avoided arguing over opinions. I attached clear evidence β€” the failing automated test, a screenshot, and the exact steps + expected vs actual from the requirement. I framed it around user/customer impact ("a customer would see a wrong balance"), not "you're wrong." We then talked to the BA/PO together to agree on priority. Result: Once the evidence was clear, we agreed it was a real issue, fixed the high-priority part before release, and logged the minor part for the next sprint. The dev and I actually worked better afterwards because I came with facts, not blame.

Why it lands: shows calm, evidence-based, collaborative behaviour β€” exactly what a big bank wants.


4. Why do you want to join Barclays?

"Three reasons. First, the domain. Barclays is a global bank, and I've been moving my career toward BFSI / fintech quality β€” testing money flows is high-stakes work where accuracy and security really matter, and I find that motivating. My background in API automation, security/VAPT testing, and building reliable frameworks fits banking well, where a single wrong number or a security gap is unacceptable. Second, the scale and engineering culture. Barclays invests heavily in technology and strong engineering practices β€” CI/CD, automation, security-first development. I want to grow as an SDET in an environment with that maturity and learn from large, well-built systems. Third, the impact. The work reaches millions of customers, so good test automation here genuinely protects people's money and trust. I'd like my automation skills to matter at that scale."

Tips: before the interview, read Barclays' latest tech news (digital banking app, their tech hubs, any AI/automation initiatives) and add one specific, current detail β€” it shows real interest. Keep it about fit + growth + impact, not just "big company."


The night-before quick list (say each in one breath)

  1. findElement = one (throws if absent); findElements = list (empty if absent).
  2. Dynamic elements β†’ stable locator (text/label) + explicit wait.
  3. Three waits: implicit (global), explicit (one condition), fluent (explicit + polling). Never mix implicit+explicit; never Thread.sleep.
  4. CSS faster; XPath can match text and go to parent.
  5. Windows: save main handle β†’ loop getWindowHandles() β†’ switch β†’ close β†’ switch back.
  6. POM = one page, one class. Tests read like business; pages hold locators.
  7. final = can't change Β· static = belongs to class Β· this = current object.
  8. ArrayList (ordered, dups), HashMap (key→value), HashSet (unique).
  9. Catch exceptions to add info / recover, not to hide; screenshot on failure.
  10. Data-driven: TestNG @DataProvider (data in code) or Excel/POI (data in sheet).
  11. Framework layers: Tests β†’ Pages β†’ API β†’ Utils β†’ Config β†’ Reports β†’ CI.
  12. Flaky = timing or data; fix root cause, retry only to measure.
  13. Parallel needs ThreadLocal driver; cross-browser often on BrowserStack/Grid.
  14. Behavioural answers = STAR, end with a result/number.
  15. Why Barclays = domain (BFSI) + engineering scale + customer impact, plus one current fact.