Skip to content
RED SAGSkills

Automation Test Engineer interview questions and answers

30 questions interviewers really ask, with what a strong answer covers. Read them, then test yourself in a timed mock interview.

Start a Automation Test Engineer mock interview

Easy questions easy

1. Why do teams automate tests, and what should not be automated?

A strong answer covers:

  • Fast, repeatable feedback on every change
  • Supports frequent releases and regression testing
  • Frees testers for exploratory work
  • Do not automate one-off, unstable or purely visual judgement checks
  • Automation has maintenance cost
Show model answer

Automation gives fast, repeatable feedback. When tests run on every pull request in CI, developers learn within minutes that a change broke checkout, instead of finding out days later from manual regression. This makes frequent releases safe and lets manual testers spend time on exploratory testing, where humans add the most value. Automated tests also run the same way every time and can cover many data combinations. But not everything should be automated. Features that change every sprint, one-time checks, usability and visual design judgement, and tests that are very hard to make stable often cost more to maintain than they save. Every automated test has a maintenance cost, so I choose tests with high value and stable behaviour, and I prefer automating at the API or unit level when possible.

2. Explain the Page Object Model and its benefits. Are there any downsides?

A strong answer covers:

  • A class per page or component holding locators and actions
  • Tests call meaningful methods instead of raw locators
  • Changes fixed in one place, less duplication
  • Downside: can grow into huge classes; avoid assertions inside page objects
  • Component objects for shared widgets
Show model answer

The Page Object Model creates a class for each page or major component. The class holds the locators and exposes actions with clear names, such as loginPage.login(email, password) or cartPage.removeItem(name). Tests use these methods, so they read like user steps and do not contain raw selectors. The big benefit is maintenance: when the login form changes, I update one page object instead of 50 tests. It also reduces duplication and makes onboarding easier. The downsides are that page objects can become huge "god classes" if a page is complex, so I split them into component objects, like Header or ProductCard. I usually keep assertions in tests rather than page objects, so the page object stays reusable. Some teams prefer lighter patterns like fixtures or the screenplay pattern, but POM is a good default.

3. What is the difference between implicit waits, explicit waits and auto-waiting?

A strong answer covers:

  • Implicit wait: global timeout for finding elements in Selenium
  • Explicit wait: wait for a specific condition on a specific element
  • Auto-waiting: frameworks like Playwright wait for actionability automatically
  • Avoid fixed sleeps and avoid mixing implicit and explicit waits
Show model answer

In Selenium, an implicit wait sets a global timeout: whenever findElement cannot find an element, it keeps trying up to that time. It only helps with element presence, not with conditions like "clickable" or "text changed". An explicit wait uses WebDriverWait with a specific condition, like elementToBeClickable or visibilityOf, for one element, which is more precise. The Selenium docs advise not to mix the two, because combined timeouts become unpredictable. Modern tools like Playwright auto-wait: before clicking, they check the element is attached, visible, stable, enabled and receives events, and web-first assertions like toHaveText keep retrying until timeout. In all tools I avoid fixed sleeps, because they make tests slow when the app is fast and still flaky when it is slow.

4. How do you run automated tests in a CI pipeline?

A strong answer covers:

  • Trigger on pull requests and merges
  • Install dependencies and browsers, often in Docker
  • Start or target a test environment
  • Run tests in parallel and publish reports and artifacts
  • Fail the build on test failures and notify the team
Show model answer

I set up a pipeline in GitHub Actions, GitLab CI or Jenkins that triggers on every pull request and on merges to main. The job checks out the code, installs dependencies, and installs browsers, often using the official Playwright or Selenium Docker image so the environment is the same everywhere. The app is either started inside the job, for example with docker compose, or the tests point to a preview environment using a base URL from environment variables, with secrets stored in the CI secret store. Tests run headless and in parallel across workers or shards. The job publishes an HTML or Allure report and uploads screenshots, videos and traces on failure. If a test fails, the build fails, so the pull request cannot be merged, and the team gets a notification. A smaller smoke suite runs on every commit, and the full suite runs nightly or before release.

5. When would you write an API test instead of a UI test?

A strong answer covers:

  • API tests are faster, more stable and cheaper to maintain
  • Good for business logic, validations and data combinations
  • UI tests for critical user journeys and UI behaviour
  • API calls can also set up data for UI tests
Show model answer

I write an API test whenever the behaviour I care about lives in the backend: validation rules, calculations, permissions, error codes and data combinations. API tests skip the browser, so they run in milliseconds instead of seconds and break less often, since they do not depend on layout or timing. For example, checking 30 discount rules is far better done through the API. I use UI tests for what only the UI can show: critical user journeys like signup to purchase, that elements display and respond correctly, and integration of frontend with backend. I keep the UI layer small, following the test pyramid. I also combine both: a UI test can create its user and data through the API first, then only test the screen it is about, which makes it faster and more reliable.

6. How do you choose locators for UI tests, and what makes a locator fragile?

A strong answer covers:

  • Prefer user-facing locators: role, label, text
  • Use stable test ids when roles are not enough
  • Avoid absolute XPath, generated classes and indexes
  • Locators should reflect what the user sees and does
  • Keep locators in one place such as page objects
Show model answer

I start with locators that match how a user finds the element: its role and accessible name, its label or its visible text. In Playwright that means getByRole or getByLabel. These survive layout and styling changes and also push the team toward accessible markup. When there is no good accessible name, for example in a dense table, I ask developers for a data-testid attribute. Fragile locators are ones tied to page structure or build output: absolute XPath, nth-child indexes, auto-generated CSS classes or long chains of divs. They break when someone wraps a button in a new container. I keep locators inside page objects or component objects so a change is fixed in one place, and I review new locators in pull requests just like any other code.

7. Explain the test pyramid. How does it guide what you automate?

A strong answer covers:

  • Many unit tests, fewer integration/API tests, few E2E tests
  • Lower levels are faster, cheaper and more precise
  • E2E tests cover only critical journeys
  • Avoid the ice-cream cone of mostly UI tests
  • Push each check to the lowest level that can catch it
Show model answer

The test pyramid says most automated tests should be fast unit tests at the bottom, a smaller layer of integration and API tests in the middle, and only a few end-to-end UI tests at the top. Lower tests run in milliseconds and point straight at the broken code. UI tests are slow, need a full environment and break for many reasons, so a suite made mostly of them, the ice-cream cone, gives slow and noisy feedback. When I plan automation I ask what the lowest level is that can catch each risk. Validation rules go in unit tests, service behaviour and error codes in API tests, and only critical journeys like sign-up and checkout get E2E tests. The pyramid is a guide, not a law, but it keeps the suite fast and trustworthy.

8. When you automate tests for a REST API endpoint, what do you check?

A strong answer covers:

  • Status codes for success and error cases
  • Response body values and schema
  • Authentication and authorisation
  • Validation of bad input and edge cases
  • Headers, side effects and response time where relevant
Show model answer

For each endpoint I check the happy path first: the exact status code, such as 201 for a create, and the important values in the body. I validate the response against the JSON schema or OpenAPI contract so missing or mistyped fields are caught. Then I cover negative cases: missing required fields and wrong types should give 400 with a clear error, no token should give 401, and a user without permission should get 403. I test boundaries like long strings, empty lists and pagination limits. I also check side effects, for example that a GET after the POST returns the new item, and key headers such as content type or caching. Where it matters I add a simple response time check, while real load testing stays in a separate suite.

9. What makes an automated test good?

A strong answer covers:

  • Tests one clear behaviour with a descriptive name
  • Independent and repeatable, creates its own data
  • Deterministic, no fixed sleeps
  • Meaningful assertions that fail with clear messages
  • Fast and easy to read and maintain
Show model answer

A good automated test checks one clear behaviour and has a name that says what is expected, so a failure is understood at a glance. It is independent: it creates or requests the data it needs and does not rely on other tests running first, so it can run alone, in any order or in parallel. It is deterministic, which means no fixed sleeps, no reliance on the real clock and no random data that can collide. Its assertions check the outcome that matters, not just that the page loaded, and when they fail they show useful messages, screenshots or traces. It is also as fast as possible, ideally at the lowest test level that can catch the risk. Finally, it is easy to read: setup, action and expected result are visible without digging through layers of helpers.

10. Compare Selenium and Playwright. When would you choose each?

A strong answer covers:

  • Selenium: W3C WebDriver standard, many languages, huge ecosystem and grids
  • Playwright: auto-waiting, browser contexts, tracing, network control
  • Playwright bundles Chromium, Firefox and WebKit
  • Choose based on team language, existing suite and needs
  • Both can run in CI and in parallel
Show model answer

Selenium is the long-standing standard. It uses the W3C WebDriver protocol, supports many languages such as Java, Python and C#, works with real branded browsers and has a huge ecosystem including Selenium Grid and cloud device providers. Selenium 4 also adds WebDriver BiDi for events. Playwright is newer and was designed for modern web apps. It auto-waits for elements, has web-first assertions, lightweight browser contexts for isolation, network mocking and an excellent trace viewer, and it ships Chromium, Firefox and WebKit. For a new web project in TypeScript or Python I usually choose Playwright because tests are faster to write and less flaky. I would keep Selenium when a company has a large working suite, needs a language Playwright does not support, or relies on an existing grid setup. The best tool also depends on team skills.

Medium questions medium

1. How would you design a test automation framework from scratch for a web app?

A strong answer covers:

  • Choose language and tools that match the team and app
  • Clear structure: tests, page or component objects, fixtures, utilities, test data
  • Configuration for environments and secrets
  • Reporting, logging, screenshots and traces
  • Parallel execution and CI integration
  • Coding standards and code review
Show model answer

I start with the context: the app's stack, the team's language skills and the browsers we must support. For a modern web app with TypeScript developers, I would pick Playwright Test, so developers can contribute too. The structure has folders for tests grouped by feature, page or component objects, fixtures for setup like authenticated users, API clients for data setup, and test data factories that create unique data. Configuration handles base URLs per environment through environment variables, with secrets kept out of the code. I add tagging for smoke and regression, retries only in CI and with flakiness tracking, and reports with traces, screenshots and videos on failure. Tests run in parallel and sharded in GitHub Actions. I add linting, including no-floating-promises, and code review rules. Finally I document how to write a new test so the framework is easy to adopt.

2. A test fails randomly in CI about 1 in 20 runs. Walk me through how you find and fix the cause.

A strong answer covers:

  • Reproduce by running it many times, locally and in CI conditions
  • Use traces, screenshots and logs from failures
  • Check common causes: timing, shared data, test order, environment, animations
  • Fix the root cause rather than adding sleeps or retries
  • Quarantine meanwhile and track flakiness
Show model answer

First I try to reproduce it: run the test 50 or 100 times, for example with Playwright's --repeat-each, with the same workers and CPU limits as CI. Then I study failure artifacts: the trace, screenshot, console and network logs. Usually the cause is one of a few things. Timing: the test acts before data loads, or uses a fixed sleep, so I switch to waiting for a specific condition or web-first assertion. Shared data: another test changes the same user, so I make data unique per test. Order dependence: the test only passes after another test ran. Environment: a slow third-party service, so I mock it. Animations or toasts covering a button. Sometimes the flakiness is a real app race condition, and then I log a bug. While I work on it, I quarantine the test so it does not block others, and I track the fix.

3. How do you manage test data in an automated suite that runs in parallel on shared environments?

A strong answer covers:

  • Create data per test via APIs or factories
  • Unique identifiers to avoid collisions
  • Clean up after tests or use disposable environments
  • Avoid dependence on pre-existing manual data
  • Seed reference data and keep secrets safe
Show model answer

My rule is that each test creates the data it needs and does not depend on anything someone created by hand. I use factory functions that call the API or database to create users, products or orders, with unique values like a UUID or timestamp in emails and names, so parallel workers never collide. Fixtures handle setup and teardown: they create the data before the test and delete it after, or the data is tagged so a nightly job cleans it. Stable reference data, like countries or product categories, is seeded once per environment by a script in version control. For heavy integration tests I prefer disposable environments, such as Testcontainers or a fresh preview environment per branch. I keep credentials in CI secrets. This makes tests independent of order and safe to run in parallel.

4. When should automated tests mock external services, and when should they use real ones?

A strong answer covers:

  • Mock to test error cases, edge data and for speed and stability
  • Real integrations needed to catch contract and configuration problems
  • Balance with contract tests
  • Keep a small number of true end-to-end tests
  • Risk of mocks drifting from reality
Show model answer

Mocks are great when I need control and stability. Third-party services like payment gateways, SMS or maps can be slow, rate-limited or unavailable in test environments, and they rarely let me trigger errors like timeouts or a declined card. With mocks, using network interception in the UI or tools like WireMock for services, I can test those cases deterministically and fast. The risk is that mocks drift away from how the real service behaves, so tests pass while production breaks. To balance this, I keep a small number of tests that hit the real sandbox, run contract tests that verify our assumptions about the provider's API, and update mocks from recorded real responses. For our own internal services, I prefer real integration in a test environment for critical flows, and mocks for everything else.

5. How do you make automated test results useful to developers and managers?

A strong answer covers:

  • Clear, fast failure messages with context
  • Artifacts such as traces, screenshots and logs linked to failures
  • Reports with trends: pass rate, flakiness, duration
  • Notify the right people at the right time
  • Link failures to commits, tickets and requirements
Show model answer

For developers, the most important thing is a failure they can understand in under a minute. I write assertions with clear messages, name tests by behaviour, and attach traces, screenshots, videos and API logs to every failure. The pull request shows exactly which test failed and links to the report. For the team and managers, I publish a report, like Allure or Playwright HTML, and a dashboard with trends: pass rate, flaky tests, suite duration, and coverage of key user journeys. Notifications go to the author of the change or the owning team, not a noisy channel everyone mutes. I link tests to requirements or tickets, so we can show which features are covered. I also review the reports in retrospectives, which helps us decide where to invest, such as fixing flaky tests or speeding up the slowest suites.

6. How do you handle authentication in a large UI test suite without making every test log in through the UI?

A strong answer covers:

  • Test the login UI itself in a few dedicated tests
  • Log in once via API or setup step and reuse session state
  • Separate state per role or user
  • Handle token expiry and parallel workers
  • Keep credentials in secrets
Show model answer

I test the login page itself thoroughly in a few dedicated tests, including wrong passwords and MFA. Every other test should not pay for it. In Playwright I use a setup project that logs in once per role, through the API where possible, and saves storage state files with the cookies and local storage. Tests then start already signed in as admin, viewer or customer by choosing the right file. In Selenium I do the same by calling the auth API and injecting the session cookie. When tests change account data, I give each parallel worker its own account so they do not interfere. I make sure tokens are refreshed if a run is long, and all credentials come from the CI secret store. This often cuts minutes from the suite while keeping real authentication in the loop.

7. Your suite needs to run in parallel across many workers. What do you change to make that safe?

A strong answer covers:

  • Remove shared mutable state and order dependencies
  • Unique test data per test or worker
  • Separate accounts or tenants for tests that change settings
  • Thread-safe driver or fresh browser contexts
  • Sharding across machines and merged reports
Show model answer

First I find shared state. Tests that depend on running in order, static drivers, or global accounts all break in parallel. I give each test its own data from factories with unique ids, so two tests never fight over the same email or cart. Tests that change global settings get their own account or tenant per worker, or they are tagged to run serially. In Selenium I make sure each thread has its own WebDriver, for example with ThreadLocal; in Playwright each test already gets a fresh browser context. I then run the suite in random order a few times to flush out hidden dependencies. To scale beyond one machine, I shard the suite in CI and merge the reports so results are still in one place. Finally I check the environment can handle the extra load.

8. Describe how you would set up automated tests in a CI/CD pipeline for a web application.

A strong answer covers:

  • Fast checks first: lint, type check, unit tests
  • API and integration tests next
  • E2E smoke on preview or staging deploy
  • Parallelism, caching and artifacts on failure
  • Quality gates block merge or release
Show model answer

On every pull request I run the fast stages first: lint, type checks and unit tests, so most mistakes fail within a few minutes. Next come API and component tests, often with services in containers. Then the app is deployed to a preview environment, and a focused E2E smoke suite runs against it with Playwright, sharded across a few machines. Failing tests upload traces, screenshots and JUnit reports as artifacts, and the results show on the pull request. These stages are required checks, so a red build blocks the merge. After merge to main, a fuller regression suite runs, and after deploying to production a short smoke and synthetic monitoring check the critical journeys. I cache dependencies and use prebuilt browser images to keep the pipeline fast, and I track flaky tests separately so the gate stays trustworthy.

9. You are asked to load test a new checkout API before a big sale. How do you plan and run it?

A strong answer covers:

  • Agree goals: expected traffic, latency and error targets
  • Realistic scenarios and data based on production patterns
  • Production-like environment and monitoring
  • Ramp up, steady load, spike and soak as needed
  • Analyse percentiles and bottlenecks, report and retest
Show model answer

I start by agreeing targets with the team: expected peak requests per second for the sale with some headroom, p95 latency targets and an acceptable error rate. I study production traffic to build realistic scenarios, like browse, add to cart and pay in the right ratios, with varied test data. I write the scripts in k6 or JMeter with thresholds so the run passes or fails clearly. The environment should be production-like in size and config, and third-party payment calls are stubbed so we do not overload partners. I watch application metrics, database and infrastructure dashboards during the run. I ramp up gradually, hold steady load, then try a spike and possibly a soak test. Afterward I report p95 and p99 latency, throughput, errors and the first bottleneck found, then retest after fixes.

10. How would you approach test automation for a mobile app on Android and iOS?

A strong answer covers:

  • Choose tools: Appium for cross-platform, Espresso/XCUITest for native speed
  • Ask developers for accessibility ids
  • Emulators for most runs, real device cloud for coverage
  • Handle permissions, deep links and app state
  • Push logic tests to API and unit level
Show model answer

First I check what the developers use. If the team wants one suite for both platforms, Appium with a shared page object layer works well. If speed and stability matter most, native frameworks like Espresso and XCUITest are faster and closer to the code, and developers can own some tests. I ask for accessibility ids on key elements so locators are stable and shared. Most runs happen on emulators and simulators in CI, with a smaller suite on a real device cloud covering the devices and OS versions our analytics show users have. I use deep links and API calls to reach screens quickly instead of tapping through every step, and I handle permission dialogs and app reset between tests. Business logic is covered by API and unit tests, so the mobile UI suite focuses on critical journeys.

Hard questions hard

1. Design a test automation strategy for a product with 15 microservices, a web app and a mobile app.

A strong answer covers:

  • Test pyramid per service: unit, component, contract tests
  • Contract testing between services
  • Small set of end-to-end journeys across web and mobile
  • Environment strategy: ephemeral environments, mocks for third parties
  • CI gates by stage with fast feedback
  • Ownership, observability and metrics
Show model answer

I would build it in layers. Each service team owns unit tests and component tests that run the service alone with its database in containers and mocks for its dependencies. Between services, consumer-driven contract tests with something like Pact catch breaking API changes in the provider's pipeline, which replaces most cross-service E2E tests. The web app has component tests and a focused Playwright suite; the mobile app uses Appium or native tools like Espresso and XCUITest for key flows. On top, a small set of end-to-end journeys, maybe 20, like signup, purchase and refund, run against a full ephemeral or staging environment, with third parties mocked or using sandboxes. CI gates: fast tests on every pull request, contracts before deploy, E2E after deploy to staging, and synthetic monitoring in production. Each test suite has a clear owner, and we track flakiness and duration as team metrics.

2. Your regression suite has grown to 3 hours. How do you bring feedback time under 15 minutes?

A strong answer covers:

  • Measure where time goes and find the slowest tests
  • Move checks down the pyramid and delete duplicates
  • Parallelise and shard across machines
  • Speed up setup with API login and data creation
  • Test impact analysis to run only affected tests on pull requests
  • Full suite runs nightly or before release
Show model answer

I start by measuring: which tests are slowest, which spend most time in setup, and which overlap. Usually a few patterns dominate. UI login and data creation in every test, so I replace them with API setup and reused authenticated state. Business rules tested through the UI, so I move them to API or unit tests and keep one UI check. Duplicate tests covering the same path, which I remove. Then I parallelise: multiple workers per machine and sharding across, say, 10 CI machines, which only works once tests are independent. For pull requests, I add test impact analysis or tags so only tests related to the changed areas run, plus a fast smoke suite, while the full suite runs on merge or nightly. I also remove fixed sleeps and slow third-party calls with mocks. With these steps, getting from 3 hours to 10 or 15 minutes is realistic.

3. What does testing in production mean, and how would you do it safely?

A strong answer covers:

  • Complements pre-release testing, does not replace it
  • Synthetic monitoring of key journeys
  • Feature flags, canary releases and gradual rollout
  • Test accounts and data isolated from real users
  • Observability with alerts and quick rollback
Show model answer

Testing in production means checking the real system with real infrastructure, data volumes and integrations, which staging can never fully match. It adds to pre-release testing; it does not replace it. One part is synthetic monitoring: automated scripts, often the same Playwright journeys, run every few minutes in production using dedicated test accounts, for example logging in and searching, and alert if they fail. Another part is safe release practices: feature flags so a feature can be turned on for internal users first, canary releases to a small percentage of traffic, and automatic rollback if error rates or latency rise. Test data must be clearly marked and isolated, so test orders are never shipped or counted in revenue. Strong observability, with logs, metrics and traces, makes problems visible quickly. Destructive tests, like heavy load, need careful planning and approval.

4. What is your view on AI-based and self-healing test automation tools in 2026?

A strong answer covers:

  • They can speed up writing tests and suggest locators
  • Self-healing can hide real UI regressions if not reviewed
  • Generated tests still need good assertions and human review
  • Good test design and stable locators still matter
  • Evaluate on reliability, transparency, cost and lock-in
Show model answer

AI tools are genuinely useful now. Coding assistants and tools like Playwright's code generation and agent features can draft tests, suggest locators and explain failures, which saves time. Self-healing locators can reduce maintenance when a button's ID changes. But I treat them as helpers, not replacements for test design. A self-healing tool that silently picks a different element can hide a real regression, so every heal must be logged and reviewed. AI-generated tests often click through flows with weak assertions, so they need human review to check that they verify meaningful behaviour. The basics still matter most: testable apps with stable test IDs and roles, independent tests, and the right pyramid. When evaluating a tool, I look at how transparent its decisions are, whether tests stay as readable code in our repo, flakiness in a real trial, cost and vendor lock-in.

5. Developers keep changing the UI and breaking your tests. How do you fix this at the team level, not just in your code?

A strong answer covers:

  • Agree on testability standards such as data-testid or accessible roles
  • Run tests on pull requests so developers see failures before merge
  • Make developers co-owners of tests
  • Use resilient locators and component-level tests
  • Show data on time lost to breakages
Show model answer

The root problem is that tests are seen as QA's responsibility only. First I make breakages visible early: tests run on every pull request, so the developer who changes the UI sees the failure before merging, not me the next morning. Second, we agree on testability standards: use semantic HTML and accessible names, which helps both users and role-based locators, and add data-testid on key elements, documented in the definition of done. I switch my tests to these resilient locators. Third, I invite developers to co-own the suite: they update affected tests in the same pull request, and I review test changes in their pull requests and vice versa. I show data, like hours lost each sprint to broken tests, to get support from the team lead. Over time, testing becomes part of how the team builds features, not a separate step.

6. How do you measure whether your test automation is healthy and worth the investment?

A strong answer covers:

  • Feedback time and pipeline duration
  • Flake rate and pass rate on unchanged code
  • Defects caught before release versus escaped defects
  • Maintenance effort and time spent fixing tests
  • Coverage of critical risks rather than raw counts
Show model answer

I avoid vanity numbers like test count. I look at a small set of signals. Feedback time: how long a developer waits for a result on a pull request. Reliability: the flake rate per test and how often the main branch is red without a real bug, because trust is the whole point. Effectiveness: defects caught by automation before release compared with escaped defects found in production, and whether escaped bugs map to gaps in our risk coverage. Cost: how many hours per sprint go into fixing broken tests and framework issues. I also review coverage of critical journeys and risks rather than raw line coverage. I share these as trends on a dashboard and use them to decide where to invest, for example deleting low-value UI tests, moving checks down to the API level, or fixing the worst flaky tests first.

7. Your company has 2,000 Selenium tests and wants to move to Playwright. How would you plan the migration?

A strong answer covers:

  • Clarify the reason and success criteria
  • Pilot on a slice and compare results
  • Run both side by side; new tests in the new tool
  • Migrate by value, delete or push down low-value tests
  • Train the team and keep shared patterns and reports
Show model answer

I would start with why. If the goals are less flakiness and faster runs, I define measurable targets, such as flake rate and suite duration. Then I run a pilot: migrate one important area, maybe 50 tests, and compare speed, stability and effort with the Selenium version. If it pays off, I avoid a big-bang rewrite. Both suites run side by side in CI, all new tests are written in Playwright, and old tests are migrated in order of value and pain, starting with the flakiest critical journeys. Many old UI tests should not be migrated at all; they can be deleted or replaced by API tests. I set up shared fixtures, page objects and reporting first so the new code is consistent, and I pair with team members to train them. The Selenium suite is retired once coverage is matched.

8. The E2E suite fails on about 30% of runs and developers now ignore it. How do you turn this around?

A strong answer covers:

  • Measure: identify which tests fail and why
  • Quarantine flaky tests out of the gate with owners and deadlines
  • Fix root causes: waits, data, environments, real bugs
  • Reduce and push tests down the pyramid
  • Protect the gate with policies and visible metrics
Show model answer

First I gather data: which tests fail most, how often they pass on rerun, and the error types. Usually a small number of tests cause most failures. I move those out of the blocking gate into a quarantine suite that still runs and reports, and each one gets an owner and a deadline, so the gate becomes green and meaningful quickly. Then I fix root causes by category: fixed sleeps replaced with proper waits, shared data replaced with unique factories, shared environment problems solved with seeded or ephemeral environments, and genuine product race conditions raised as bugs. I also question whether every E2E test is needed and move checks to the API level. Finally I agree on a team policy: new tests must pass many repeated runs before joining the gate, and flake rate is shown on a dashboard so trust is earned back visibly.

9. How do you design automated tests for an event-driven microservices system where services talk through a message broker?

A strong answer covers:

  • Unit test handlers with in-memory events
  • Component tests with a real broker in containers
  • Contract tests or schema registry for event shapes
  • Poll with timeouts for async outcomes, use correlation ids
  • Test retries, duplicates, ordering and dead-letter queues
Show model answer

I test at several levels. Each event handler gets unit tests with in-memory events, covering business rules. Then component tests run each service with a real broker, like Kafka or RabbitMQ, started in containers with Testcontainers: publish an event, then poll with a timeout until the expected side effect appears, never fixed sleeps. Event shapes are protected with contract tests or a schema registry with compatibility rules, so a producer cannot break consumers silently. Event-driven systems fail in special ways, so I deliberately test duplicate delivery to prove handlers are idempotent, out-of-order events, consumer crashes and retries, and that poison messages land in the dead-letter queue. A few end-to-end tests cover critical flows using correlation ids so I can trace one order through every service and debug failures from logs.

10. Your product adds an AI assistant built on a large language model. Its answers vary between runs. How would you automate testing for it?

A strong answer covers:

  • Test deterministic parts normally: prompts building, tools, APIs, UI
  • Use evaluation sets with rubric or property checks, not exact matches
  • LLM-as-judge or human review with care and calibration
  • Track pass rates over many runs and set thresholds
  • Safety, prompt injection and regression on model changes
Show model answer

I separate what is deterministic from what is not. Prompt building, tool calls, API handling, error states and the UI get normal tests, and in UI tests I mock the model so they are stable. For the model behaviour itself I build an evaluation set of realistic questions with expected properties instead of exact text: the answer mentions the refund policy, cites a source, stays under a length, uses the right tool, or refuses unsafe requests. Checks combine code-based rules with an LLM-as-judge using a clear rubric, calibrated against human ratings. Because outputs vary, I run each case several times and track pass rates against a threshold rather than single pass or fail. The eval suite runs whenever prompts or model versions change, and it includes prompt injection and data leakage cases so safety regressions are caught before release.