SDET Interview Rounds by Company (2026)
Round-by-round interview process, real sample questions with answers, and prep tips for 15 top companies hiring SDET and QA engineers.
Amazon Interview Process
FAANG · E-Commerce · AWS · Seattle USA · 5–6 Rounds
💻 Online Assessment (OA)
90-minute HackerTest with 2 coding problems (Medium) + Work Simulation. Focus: Arrays, Strings, HashMap, Sliding Window, BFS/DFS. Amazon's OA bar for SDET is slightly lower than SDE but still needs clean working code with edge cases.
public int lengthOfLongestSubstring(String s) {
Map<Character,Integer> map = new HashMap<>();
int maxLen = 0, left = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
if (map.containsKey(c))
left = Math.max(left, map.get(c) + 1);
map.put(c, right);
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
// "abcabcbb"→3 "bbbbb"→1 ""→0 "pwwkew"→3 target - nums[i] already exists in the map. O(n) time, O(n) space.public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> seen = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (seen.containsKey(complement))
return new int[]{seen.get(complement), i};
seen.put(nums[i], i);
}
return new int[]{};
}
// [2,7,11,15] target=9 → [0,1] [3,3] target=6 → [0,1] public int search(int[] nums, int target) {
int lo = 0, hi = nums.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (nums[mid] == target) return mid;
if (nums[lo] <= nums[mid]) { // left half sorted
if (target >= nums[lo] && target < nums[mid])
hi = mid - 1;
else lo = mid + 1;
} else { // right half sorted
if (target > nums[mid] && target <= nums[hi])
lo = mid + 1;
else hi = mid - 1;
}
}
return -1;
}
// [4,5,6,7,0,1,2] target=0 → 4 target=3 → -1 class MinStack {
private Deque<Integer> stack = new ArrayDeque<>();
private Deque<Integer> minStack = new ArrayDeque<>();
public void push(int val) {
stack.push(val);
int newMin = minStack.isEmpty() ? val : Math.min(val, minStack.peek());
minStack.push(newMin);
}
public void pop() { stack.pop(); minStack.pop(); }
public int top() { return stack.peek(); }
public int getMin(){ return minStack.peek(); }
} public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> map = new HashMap<>();
for (String s : strs) {
char[] c = s.toCharArray();
Arrays.sort(c);
String key = new String(c);
map.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
}
return new ArrayList<>(map.values());
}
// ["eat","tea","tan","ate","nat","bat"]
// → [["eat","tea","ate"],["tan","nat"],["bat"]] public boolean isPalindrome(String s) {
int lo = 0, hi = s.length() - 1;
while (lo < hi) {
while (lo < hi && !Character.isLetterOrDigit(s.charAt(lo))) lo++;
while (lo < hi && !Character.isLetterOrDigit(s.charAt(hi))) hi--;
if (Character.toLowerCase(s.charAt(lo)) !=
Character.toLowerCase(s.charAt(hi))) return false;
lo++; hi--;
}
return true;
}
// "A man, a plan, a canal: Panama" → true
// "race a car" → false public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size(); // capture level size!
List<Integer> level = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(level);
}
return result;
} public List<String> generateParenthesis(int n) {
List<String> result = new ArrayList<>();
backtrack(result, new StringBuilder(), 0, 0, n);
return result;
}
private void backtrack(List<String> res, StringBuilder cur,
int open, int close, int n) {
if (cur.length() == 2 * n) { res.add(cur.toString()); return; }
if (open < n) {
cur.append("(");
backtrack(res, cur, open + 1, close, n);
cur.deleteCharAt(cur.length() - 1);
}
if (close < open) {
cur.append(")");
backtrack(res, cur, open, close + 1, n);
cur.deleteCharAt(cur.length() - 1);
}
}
// n=3 → ["((()))","(()())","(())()","()(())","()()()"] public int rob(int[] nums) {
if (nums.length == 0) return 0;
if (nums.length == 1) return nums[0];
int prev2 = 0, prev1 = 0;
for (int n : nums) {
int curr = Math.max(prev1, prev2 + n);
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
// [2,7,9,3,1] → 12 (2+9+1)
// [1,2,3,1] → 4 (1+3) public int numIslands(char[][] grid) {
int count = 0;
for (int i = 0; i < grid.length; i++)
for (int j = 0; j < grid[0].length; j++)
if (grid[i][j] == "1") { dfs(grid,i,j); count++; }
return count;
}
private void dfs(char[][] g, int i, int j) {
if (i<0||i>=g.length||j<0||j>=g[0].length||g[i][j]!="1") return;
g[i][j] = "0"; // mark visited
dfs(g,i+1,j); dfs(g,i-1,j); dfs(g,i,j+1); dfs(g,i,j-1);
}
// [["1","1","0"],["1","1","0"],["0","0","1"]] → 2 🔬 Technical Round 1
Deep dive into Selenium internals, Java OOP, TestNG, and framework architecture. The interviewer will ask you to write live code. Amazon values "working backwards" — always explain WHY you chose each design before HOW.
// BasePage.java
public class BasePage {
protected WebDriver driver;
protected WebDriverWait wait;
public BasePage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(15));
PageFactory.initElements(driver, this);
}
protected void click(By by) {
wait.until(ExpectedConditions.elementToBeClickable(by)).click();
}
protected void type(By by, String text) {
WebElement el = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
el.clear(); el.sendKeys(text);
}
}
// CheckoutPage.java
public class CheckoutPage extends BasePage {
@FindBy(id="placeYourOrder") private WebElement placeOrderBtn;
public CheckoutPage(WebDriver d) { super(d); }
public OrderConfirmPage placeOrder() {
placeOrderBtn.click();
return new OrderConfirmPage(driver);
}
}
// BaseTest.java
public class BaseTest {
@BeforeMethod @Parameters("browser")
public void setUp(@Optional("chrome") String browser) {
DriverFactory.initDriver(browser);
}
@AfterMethod(alwaysRun=true)
public void tearDown() { DriverFactory.quitDriver(); }
} // RetryAnalyzer.java
public class RetryAnalyzer implements IRetryAnalyzer {
private int count = 0;
private static final int MAX = 2; // retry up to 2 times
@Override
public boolean retry(ITestResult result) {
if (count < MAX) { count++; return true; }
return false;
}
}
// Usage in test method
@Test(retryAnalyzer = RetryAnalyzer.class)
public void checkoutFlowTest() { ... }
// Or apply globally via TestNG listener
public class RetryListener implements IAnnotationTransformer {
@Override
public void transform(ITestAnnotation annotation, ...) {
annotation.setRetryAnalyzer(RetryAnalyzer.class);
}
} // Explicit Wait - recommended
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
WebElement el = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("toast")));
// Fluent Wait - for intermittent elements
Wait<WebDriver> fluent = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(20))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class)
.ignoring(StaleElementReferenceException.class);
WebElement btn = fluent.until(d -> d.findElement(By.id("submit")));
// Custom condition
wait.until(d -> d.findElement(By.id("count"))
.getText().equals("10")); public class DriverFactory {
private static final ThreadLocal<WebDriver> pool = new ThreadLocal<>();
public static WebDriver getDriver() { return pool.get(); }
public static void initDriver(String browser) {
WebDriver d = switch(browser.toLowerCase()) {
case "firefox" -> new FirefoxDriver();
case "edge" -> new EdgeDriver();
default -> {
ChromeOptions o = new ChromeOptions();
o.addArguments("--headless=new","--no-sandbox");
yield new ChromeDriver(o);
}
};
d.manage().window().maximize();
pool.set(d);
}
public static void quitDriver() {
if (pool.get() != null) {
pool.get().quit();
pool.remove(); // CRITICAL: prevents memory leak
}
}
}
// testng.xml: <suite parallel="methods" thread-count="5"> // Simple DataProvider
@DataProvider(name = "loginData")
public Object[][] loginDataProvider() {
return new Object[][] {
{"admin@test.com", "Pass123", true},
{"wrong@test.com", "wrongPass", false},
{"", "pass", false},
{"admin@test.com", "", false},
};
}
@Test(dataProvider = "loginData")
public void loginTest(String email, String pwd, boolean expected) {
boolean result = loginPage.login(email, pwd);
Assert.assertEquals(result, expected);
}
// Excel-driven (Apache POI)
@DataProvider(name = "excelData")
public Object[][] fromExcel() throws Exception {
FileInputStream fis = new FileInputStream("testdata.xlsx");
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sheet = wb.getSheetAt(0);
int rows = sheet.getLastRowNum() + 1;
Object[][] data = new Object[rows - 1][2];
for (int i = 1; i < rows; i++) {
XSSFRow row = sheet.getRow(i);
data[i-1][0] = row.getCell(0).getStringCellValue();
data[i-1][1] = row.getCell(1).getStringCellValue();
}
wb.close();
return data;
} public class TestListener implements ITestListener {
@Override
public void onTestFailure(ITestResult result) {
captureScreenshot(result.getName());
}
@Attachment(value = "Failure Screenshot", type = "image/png")
private byte[] captureScreenshot(String testName) {
return ((TakesScreenshot) DriverFactory.getDriver())
.getScreenshotAs(OutputType.BYTES);
}
}
// In Allure - attach in test itself
@Attachment(value = "Page Screenshot", type = "image/png")
public static byte[] takeScreenshot() {
return ((TakesScreenshot) DriverFactory.getDriver())
.getScreenshotAs(OutputType.BYTES);
}
// testng.xml
// <listener class-name="com.pkg.TestListener"/> // API-based login for faster test setup
@BeforeMethod
public void setUp() {
// Instead of Selenium login (15-20s):
String token = ApiClient.post("/auth/login",
Map.of("email","test@co.com","pwd","pass")).path("token");
// Inject cookie into browser - instant!
DriverFactory.initDriver("chrome");
driver.get(BASE_URL); // navigate first
driver.manage().addCookie(
new Cookie("session", token, "/"));
driver.navigate().refresh();
} // Jenkinsfile - PR Pipeline
pipeline {
agent any
triggers { githubPush() }
stages {
stage("Smoke Tests") {
steps {
sh "mvn test -Dgroups=smoke -Dbrowser=chrome -Denv=staging -q"
}
post {
always { junit "target/surefire-reports/*.xml" }
failure { slackSend "#qa-alerts", "PR SMOKE FAILED: ${env.BUILD_URL}" }
}
}
}
}
// Nightly Pipeline
pipeline {
agent any
triggers { cron("0 2 * * *") }
stages {
stage("Regression - Parallel") {
parallel {
stage("Chrome") { steps { sh "mvn test -Dbrowser=chrome -Dgroups=regression" } }
stage("Firefox") { steps { sh "mvn test -Dbrowser=firefox -Dgroups=regression" } }
stage("Edge") { steps { sh "mvn test -Dbrowser=edge -Dgroups=regression" } }
}
}
stage("Allure Report") {
steps { allure results: [[path: "target/allure-results"]] }
}
}
} @Test
public void createAndVerifyOrder() {
// Step 1: Create order
String orderId = given()
.baseUri(BASE_URL)
.header("Authorization", "Bearer " + getToken())
.header("Idempotency-Key", UUID.randomUUID().toString()) // prevent duplicates
.contentType(ContentType.JSON)
.body("{ \"productId\": \"B01N5IB20Q\", \"qty\": 2 }")
.when()
.post("/orders")
.then()
.statusCode(201)
.body("status", equalTo("CREATED"))
.time(lessThan(2000L)) // SLA assertion
.extract().path("orderId");
// Step 2: Verify GET returns same details
given()
.baseUri(BASE_URL)
.header("Authorization", "Bearer " + getToken())
.pathParam("id", orderId)
.when()
.get("/orders/{id}")
.then()
.statusCode(200)
.body("orderId", equalTo(orderId))
.body("status", equalTo("CREATED"))
.body("productId", equalTo("B01N5IB20Q"))
.body("qty", equalTo(2));
} // Thread-safe test data pool
public class TestDataPool {
private static final ConcurrentLinkedQueue<TestUser> pool = new ConcurrentLinkedQueue<>();
static {
// Pre-load 500 test users at suite start
for (int i = 0; i < 500; i++) {
pool.offer(new TestUser("user"+i+"@test.com", "Pass"+i));
}
}
public static TestUser borrow() { return pool.poll(); }
public static void release(TestUser u) { pool.offer(u); }
}
// In test
public class CheckoutTest extends BaseTest {
private TestUser user;
@BeforeMethod
public void setUp() {
user = TestDataPool.borrow(); // get exclusive user
}
@AfterMethod
public void tearDown() {
TestDataPool.release(user); // return to pool
DriverFactory.quitDriver();
}
} 🔌 Technical Round 2 — API & CI/CD
Focus on REST API testing, REST Assured, Postman, Jenkins pipelines, and Docker. Expect live coding of API test scenarios. Amazon SDETs own their test pipelines — show you can build and maintain them end-to-end.
public class OrderLifecycleTest {
private RequestSpecification spec;
private String orderId, cartId;
@BeforeClass
public void setup() {
spec = new RequestSpecBuilder()
.setBaseUri(BASE_URL)
.addHeader("Authorization", "Bearer " + getToken())
.setContentType(ContentType.JSON)
.log(LogDetail.BODY).build();
}
@Test(priority=1)
public void createOrder() {
orderId = given(spec)
.body("{\"customerId\":\"C001\"}")
.when().post("/orders")
.then().statusCode(201)
.extract().path("orderId");
}
@Test(priority=2, dependsOnMethods="createOrder")
public void addItem() {
given(spec)
.pathParam("id", orderId)
.body("{\"productId\":\"P001\",\"qty\":3}")
.when().post("/orders/{id}/items")
.then().statusCode(200)
.body("itemCount", equalTo(1));
}
@Test(priority=3, dependsOnMethods="addItem")
public void checkout() {
given(spec).pathParam("id", orderId)
.when().post("/orders/{id}/checkout")
.then().statusCode(200)
.body("status", equalTo("CONFIRMED"));
}
} // schema: src/test/resources/schemas/order-schema.json
// {
// "type": "object",
// "required": ["orderId","status","total"],
// "properties": {
// "orderId": {"type":"string"},
// "status": {"type":"string","enum":["CREATED","CONFIRMED","SHIPPED"]},
// "total": {"type":"number","minimum":0}
// }
// }
@Test
public void validateOrderSchema() {
given()
.baseUri(BASE_URL)
.header("Authorization", "Bearer " + getToken())
.when()
.get("/orders/ORD-001")
.then()
.statusCode(200)
.body(matchesJsonSchemaInClasspath("schemas/order-schema.json"));
}
// pom.xml dependency:
// <dependency>
// <groupId>io.rest-assured</groupId>
// <artifactId>json-schema-validator</artifactId>
// </dependency> public class TokenManager {
private static String token;
private static long tokenExpiry = 0;
public static synchronized String getToken() {
if (System.currentTimeMillis() > tokenExpiry) {
Response res = given()
.formParam("grant_type", "client_credentials")
.formParam("client_id", Config.get("client.id"))
.formParam("client_secret", Config.get("client.secret"))
.post(AUTH_URL + "/token");
token = res.path("access_token");
int expiresIn = res.path("expires_in");
tokenExpiry = System.currentTimeMillis() + (expiresIn - 60) * 1000L;
}
return token;
}
}
// Usage in test
@Test
public void protectedEndpoint() {
given()
.header("Authorization", "Bearer " + TokenManager.getToken())
.when()
.get("/protected/resource")
.then()
.statusCode(200);
} @DataProvider(name = "negativePayments")
public Object[][] negativePaymentData() {
return new Object[][] {
// body, expectedStatus, expectedError
{"{}", 400, "amount is required"},
{"{\"amount\":0, \"currency\":\"INR\", \"vpa\":\"a@upi\"}", 400, "amount must be positive"},
{"{\"amount\":-100, \"currency\":\"INR\", \"vpa\":\"a@upi\"}", 400, "amount must be positive"},
{"{\"amount\":200001, \"currency\":\"INR\", \"vpa\":\"a@upi\"}", 422, "exceeds daily limit"},
{"{\"amount\":100, \"currency\":\"XYZ\", \"vpa\":\"a@upi\"}", 400, "unsupported currency"},
{"{\"amount\":100, \"currency\":\"INR\", \"vpa\":\"invalid-vpa\"}", 400, "invalid VPA format"},
};
}
@Test(dataProvider = "negativePayments")
public void negativePaymentTest(String body, int status, String errorMsg) {
given()
.header("Authorization", "Bearer " + getToken())
.contentType(ContentType.JSON)
.body(body)
.when()
.post("/payments")
.then()
.statusCode(status)
.body("error.message", containsString(errorMsg));
} .time(lessThan(Xms)) for response time assertions. Combine with custom reporting for SLA trend monitoring.@Test
public void checkoutAPI_ShouldRespondWithin1Second() {
long startTime = System.currentTimeMillis();
given()
.baseUri(BASE_URL)
.header("Authorization", "Bearer " + getToken())
.contentType(ContentType.JSON)
.body("{\"cartId\":\"C001\",\"paymentMethod\":\"UPI\"}")
.when()
.post("/checkout")
.then()
.statusCode(200)
.time(lessThan(1000L)) // SLA: must respond within 1 second
.body("status", equalTo("SUCCESS"));
// Log for SLA trend dashboard
long duration = System.currentTimeMillis() - startTime;
SlaReporter.record("POST /checkout", duration, 1000);
System.out.println("Checkout API: " + duration + "ms");
}
// Critical API SLAs (typical Amazon):
// GET /products < 200ms
// POST /cart < 300ms
// POST /checkout < 1000ms
// POST /payments < 3000ms (payment gateway latency) @Test
public void paymentIdempotency_SameKey_NoDoubleCharge() {
String idempotencyKey = "test-idem-" + UUID.randomUUID();
String body = "{\"amount\":500,\"currency\":\"INR\",\"vpa\":\"test@upi\"}";
// First call - creates payment
String paymentId1 = given()
.header("Idempotency-Key", idempotencyKey)
.header("Authorization", "Bearer " + getToken())
.contentType(ContentType.JSON).body(body)
.when().post("/payments")
.then().statusCode(201)
.extract().path("paymentId");
// Second call - same key, must NOT create new payment
Response second = given()
.header("Idempotency-Key", idempotencyKey)
.header("Authorization", "Bearer " + getToken())
.contentType(ContentType.JSON).body(body)
.when().post("/payments")
.then()
.statusCode(anyOf(equalTo(200), equalTo(201)))
.body("idempotent", equalTo(true))
.extract().response();
String paymentId2 = second.path("paymentId");
Assert.assertEquals(paymentId1, paymentId2,
"Same idempotency key should return same paymentId");
} // WireMock webhook test
@Test
public void orderWebhook_StatusChange_ShouldFire() {
// Start local mock server
WireMockServer mock = new WireMockServer(8099);
mock.start();
// Register webhook listener in system
given().baseUri(BASE_URL)
.body("{\"url\":\"http://localhost:8099/webhook\",\"events\":[\"order.shipped\"]}")
.post("/webhooks/register");
// Configure WireMock to capture the call
mock.stubFor(post(urlEqualTo("/webhook")).willReturn(ok()));
// Trigger order status change
given().baseUri(BASE_URL)
.body("{\"status\":\"SHIPPED\"}")
.patch("/orders/ORD-001/status");
// Wait and verify webhook received
await().atMost(10, SECONDS).untilAsserted(() -> {
mock.verify(1, postRequestedFor(urlEqualTo("/webhook"))
.withRequestBody(containing("\"event\":\"order.shipped\""))
.withRequestBody(containing("\"orderId\":\"ORD-001\"")));
});
mock.stop();
} public class PerformanceBaseline {
private static final Map<String, Long> baseline = Map.of(
"GET /products", 180L,
"POST /cart", 250L,
"POST /checkout", 800L
);
public static void assertNoRegression(String endpoint, long actualMs) {
Long baselineMs = baseline.get(endpoint);
if (baselineMs != null) {
long threshold = (long)(baselineMs * 1.10); // 10% regression allowed
Assert.assertTrue(actualMs <= threshold,
String.format("%s regressed: was %dms, now %dms (limit: %dms)",
endpoint, baselineMs, actualMs, threshold));
}
}
}
// In test:
@Test
public void productSearch_ShouldNotRegress() {
long start = System.nanoTime();
given().baseUri(BASE_URL).get("/products?q=laptop").then().statusCode(200);
long durationMs = (System.nanoTime() - start) / 1_000_000;
PerformanceBaseline.assertNoRegression("GET /products", durationMs);
} // Consumer side (e.g., Frontend calling Order API)
@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(providerName = "OrderService")
public class OrderServiceConsumerTest {
@Pact(consumer = "FrontendApp")
public RequestResponsePact createPact(PactDslWithProvider builder) {
return builder
.given("order ORD-001 exists")
.uponReceiving("a request to get order ORD-001")
.path("/orders/ORD-001")
.method("GET")
.headers(Map.of("Authorization", "Bearer token"))
.willRespondWith()
.status(200)
.body(new PactDslJsonBody()
.stringType("orderId")
.stringValue("status", "CONFIRMED")
.decimalType("total"))
.toPact();
}
@Test
@PactTestFor(pactMethod = "createPact")
public void verifyOrderAPI(MockServer mock) {
// Test against Pact mock server (no real service needed)
given().baseUri(mock.getUrl())
.get("/orders/ORD-001")
.then().statusCode(200);
}
} @Test
public void idor_ShouldNotAccessOtherUsersOrder() {
// Create order as User A
String tokenA = getToken("userA@test.com", "passA");
String orderId = given().header("Authorization","Bearer "+tokenA)
.post("/orders").then().extract().path("orderId");
// Try to access User A order as User B - should fail
String tokenB = getToken("userB@test.com", "passB");
given()
.header("Authorization","Bearer "+tokenB)
.pathParam("id", orderId)
.when()
.get("/orders/{id}")
.then()
.statusCode(403); // Forbidden - not 200!
}
@Test
public void authBypass_NoToken_ShouldReturn401() {
given().baseUri(BASE_URL)
.when().get("/orders/ORD-001")
.then().statusCode(401);
}
@Test
public void sqlInjection_ShouldNotReturnData() {
given().baseUri(BASE_URL)
.header("Authorization","Bearer "+getToken())
.queryParam("productId", "1 OR 1=1; DROP TABLE orders;--")
.when().get("/products")
.then().statusCode(anyOf(equalTo(400), equalTo(404)))
.body("products", is(empty()));
} ⭐ Bar Raiser
The most important Amazon round. An interviewer from a DIFFERENT team ensures you meet Amazon's bar. Almost entirely behavioral using STAR format. Every answer must map to Amazon's 16 Leadership Principles. Most common for SDET: Customer Obsession, Dive Deep, Insist on Highest Standards, Ownership.
// Always prepare STAR stories in this format: // S - Situation (2-3 sentences, set the context) // T - Task (what was YOUR specific responsibility) // A - Action (what YOU specifically did - use "I" not "we") // R - Result (quantified: %, ₹, time saved, users affected) // Key metrics to have ready: // - % improvement in defect escape rate // - Time reduction in test suite execution // - Number of bugs prevented from reaching production // - Business impact in rupees or user count
// Ownership LP in practice: // 1. Never say "that's not my job" in an Amazon interview // 2. Show you go BEYOND your immediate scope when quality is at risk // 3. Demonstrate you FOLLOWED THROUGH to completion // 4. Quantify how YOUR ownership changed the outcome // Anti-patterns that FAIL the Bar Raiser: // ❌ "I told my manager about it" // ❌ "I filed a bug report and moved on" // ❌ "The team eventually fixed it" // ✅ "I dug in, understood the root cause, proposed the fix, and verified it"
// Dive Deep investigative framework: // 1. Reproduce: Can you make it happen consistently? // 2. Isolate: Which component/layer is failing? // 3. Correlate: Does it correlate with time/load/data patterns? // 4. Hypothesize: Form 3 hypotheses, rank by likelihood // 5. Test: Prove/disprove each hypothesis with data // 6. Fix: Change ONE thing at a time // 7. Confirm: Run 100 iterations to confirm fix holds // 8. Prevent: Add test/alert so it never recurs silently
// Bug triage framework Priority P0: blocks core user journey → MUST FIX, release blocked Priority P1: affects many users, has workaround→ fix before release Priority P2: affects few users, low impact → next sprint Priority P3: cosmetic, extremely rare → backlog // Questions for each bug: // 1. How many customers hit this per day? // 2. Does it cause financial or data loss? // 3. Is there a workaround customers can use? // 4. How long to fix vs impact of delay? // Amazon principle: "Start with the customer and work backwards" // Never: "This is easy to fix so let's do it first"
// Disagree and Commit pattern: // Step 1: Disagree with DATA, not opinion // "I disagree because our benchmarks show X" // NOT "I disagree because I prefer Y" // Step 2: Present your position with evidence // PoC, benchmarks, team survey, cost analysis // Step 3: Clearly state your recommendation // "Based on this data, I recommend A over B" // Step 4: If decision goes against you - COMMIT // "I understand. I'll make B work as well as possible." // NOT: "I told you so" when it doesn't work // What NOT to say: // ❌ "I just went along with it" // ❌ "I kept pushing until I won" // ❌ "I implemented it badly because I disagreed"
// Bias for Action decision framework: // 1. What is the reversibility? (Can we roll back easily?) // 2. What is the real blast radius? (Not theoretical worst case) // 3. What data do I have RIGHT NOW? // 4. Can I get 70% confidence in 10 minutes? // 5. Document reasoning BEFORE deciding // 6. Set up monitoring to catch if wrong // 7. Have rollback ready // Amazon two-pizza rule: teams should be small enough // that two pizzas can feed them - same applies to decisions: // If decision affects your squad, you can make it. // Escalate only when it crosses squad boundary.
// Earn Trust after failure - the playbook: // 1. ACKNOWLEDGE: No defensive language. "I made a mistake." // 2. IMPACT: Quantify exactly what happened // 3. ROOT CAUSE: Show you investigated deeply // 4. FIX: What exactly did you do to repair it? // 5. PREVENTION: What changed in the process to prevent recurrence? // 6. FOLLOW-UP: Did the prevention actually work? // The worst answers: // ❌ Blame external factors // ❌ Minimize the impact // ❌ Promise to "be more careful" (not a system fix) // ✅ Systemic change that prevented future occurrences
// Structured interview I would design:
// Round 1: Live test case writing (not just "write 10 test cases"
// but "here is a feature spec with gaps - find them")
// Round 2: Debugging session (I give them a broken Selenium test
// and watch how they investigate, not just fix)
// Round 3: System design ("how would you test Alexa's response
// quality across 50 languages")
// Round 4: Behavioral (ownership, conflict, failure stories)
// Red flags I would look for:
// - Says "100% coverage" as a goal (quality theater)
// - Never modified or challenged a process
// - No specific numbers in any achievement
// - "Testing is about finding bugs" (missing prevention) // The evolving SDET role: // 2020: Write manual tests → automate them // 2023: Design automation frameworks + own CI/CD pipelines // 2025: Observability-driven + chaos engineering + AI-assisted // 2028: AI generates tests, SDET validates strategy + coverage // Skills to build NOW for future-proof career: // 1. Prompt engineering for test generation (ChatGPT, Copilot) // 2. Distributed systems understanding (test what you cant replicate) // 3. Chaos engineering (LitmusChaos, Gremlin) // 4. Contract testing (Pact for microservices) // 5. eBPF + observability (test via production signals)
// Cost optimization for test infrastructure: // 1. Auto-scaling Grid nodes (on-demand not 24/7) // EC2 on-demand vs Reserved vs Spot for batch test runs // 2. Headless browsers (no GUI = lower CPU) // 3. API setup instead of UI setup (10x faster, lower resource) // 4. TestContainers instead of persistent test environments // 5. Test quarantine (remove flaky tests = less re-runs) // 6. Smoke-first pipeline (fail fast, dont run full suite on bad build) // Calculate monthly test infrastructure cost: // Instances × hours × AWS rate = monthly cost // Compare with developer time saved from faster pipelines // ROI must be positive
Google Interview Process
FAANG · Search · GCP · Android · Mountain View USA · 5–7 Rounds
💻 Coding Round
Google's coding round for SET/TE is IDENTICAL to SWE rounds — LeetCode Medium/Hard. Google values communication as much as correctness. Always explain your approach before typing. Ask clarifying questions. Mention time and space complexity without being asked.
public boolean isBalanced(String s) {
Deque<Character> stack = new ArrayDeque<>();
Map<Character,Character> pairs = Map.of(")","(", "]","[", "}","{");
for (char c : s.toCharArray()) {
if (pairs.containsValue(c)) stack.push(c);
else if (pairs.containsKey(c))
if (stack.isEmpty() || stack.pop() != pairs.get(c)) return false;
}
return stack.isEmpty();
}
// "([]{})"→true "([)]"→false "{"→false ""→true // Recursive - clean and elegant
public int maxDepth(TreeNode root) {
if (root == null) return 0;
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}
// Iterative BFS - mention both to Google
public int maxDepthBFS(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root); int depth = 0;
while (!q.isEmpty()) {
depth++;
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode n = q.poll();
if (n.left != null) q.offer(n.left);
if (n.right != null) q.offer(n.right);
}
}
return depth;
} public int numIslands(char[][] grid) {
int count = 0;
for (int i = 0; i < grid.length; i++)
for (int j = 0; j < grid[0].length; j++)
if (grid[i][j] == "1") { dfs(grid,i,j); count++; }
return count;
}
private void dfs(char[][] g, int i, int j) {
if (i<0||i>=g.length||j<0||j>=g[0].length||g[i][j]!="1") return;
g[i][j]="0";
dfs(g,i+1,j); dfs(g,i-1,j); dfs(g,i,j+1); dfs(g,i,j-1);
}
// [["1","1","0"],["1","1","0"],["0","0","1"]] → 2 public int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
int slow = 0;
for (int fast = 1; fast < nums.length; fast++) {
if (nums[fast] != nums[slow]) {
slow++;
nums[slow] = nums[fast];
}
}
return slow + 1; // length = index + 1
}
// [1,1,2] → 2, nums=[1,2,...]
// [0,0,1,1,1,2] → 3, nums=[0,1,2,...] public String longestPalindrome(String s) {
int start = 0, maxLen = 1;
for (int i = 0; i < s.length(); i++) {
// Odd length palindromes (center at i)
int len1 = expandAroundCenter(s, i, i);
// Even length palindromes (center between i and i+1)
int len2 = expandAroundCenter(s, i, i+1);
int len = Math.max(len1, len2);
if (len > maxLen) {
maxLen = len;
start = i - (len - 1) / 2;
}
}
return s.substring(start, start + maxLen);
}
private int expandAroundCenter(String s, int lo, int hi) {
while (lo >= 0 && hi < s.length() && s.charAt(lo) == s.charAt(hi)) {
lo--; hi++;
}
return hi - lo - 1;
}
// "babad"→"bab" "cbbd"→"bb" "a"→"a" public int firstUniqChar(String s) {
Map<Character,Integer> freq = new HashMap<>();
for (char c : s.toCharArray())
freq.merge(c, 1, Integer::sum);
for (int i = 0; i < s.length(); i++)
if (freq.get(s.charAt(i)) == 1) return i;
return -1;
}
// "leetcode"→0 "loveleetcode"→2 "aabb"→-1 public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a,b) -> a[0] - b[0]);
List<int[]> merged = new ArrayList<>();
for (int[] cur : intervals) {
if (merged.isEmpty() || merged.get(merged.size()-1)[1] < cur[0])
merged.add(cur);
else
merged.get(merged.size()-1)[1] = Math.max(
merged.get(merged.size()-1)[1], cur[1]);
}
return merged.toArray(new int[0][]);
}
// [[1,3],[2,6],[8,10],[15,18]] → [[1,6],[8,10],[15,18]] public int mySqrt(int x) {
if (x < 2) return x;
int lo = 1, hi = x / 2, result = 0;
while (lo <= hi) {
long mid = lo + (hi - lo) / 2; // long to prevent overflow
if (mid * mid == x) return (int) mid;
else if (mid * mid < x) { result = (int) mid; lo = (int)(mid+1); }
else hi = (int)(mid-1);
}
return result;
}
// 4→2 8→2 9→3 1→1 0→0 public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
backtrack(result, new ArrayList<>(), nums, 0);
return result;
}
private void backtrack(List<List<Integer>> res, List<Integer> cur,
int[] nums, int start) {
res.add(new ArrayList<>(cur)); // add current subset
for (int i = start; i < nums.length; i++) {
cur.add(nums[i]);
backtrack(res, cur, nums, i+1);
cur.remove(cur.size()-1); // backtrack
}
}
// [1,2,3] → [[],[1],[1,2],[1,2,3],[1,3],[2],[2,3],[3]]
// 2^n subsets total public int[] findTopK(int[] nums, int k) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>(k);
for (int n : nums) {
if (minHeap.size() < k) minHeap.offer(n);
else if (n > minHeap.peek()) {
minHeap.poll();
minHeap.offer(n);
}
}
return minHeap.stream().mapToInt(x->x).toArray();
}
// [3,2,1,5,6,4] k=2 → [5,6]
// [1] k=1 → [1]
// Time: O(n log k) Space: O(k)
// vs Sort: O(n log n) time O(1) space
// Heap wins when k << n 🧪 Test Design Round
Google's most unique round. Asked to "test X" where X is often abstract — a vending machine, elevator, Google Search. They evaluate STRUCTURED THINKING, not tool knowledge. Use: Functional → Edge Cases → Non-Functional → Security → Accessibility → Negative.
// Test Design Structure Template: // 1. CLARIFY: What exactly is in scope? // 2. FUNCTIONAL: What should it DO correctly? // 3. EDGE CASES: What unusual inputs break it? // 4. NEGATIVE: What should it REJECT? // 5. NON-FUNCTIONAL: Performance, Security, Reliability // 6. ACCESSIBILITY: WCAG 2.1 compliance // 7. COMPATIBILITY: Browsers, devices, OS // 8. LOCALIZATION: Multiple languages, RTL text
// State Machine test approach for vending machine: // States: IDLE → AWAITING_SELECTION → DISPENSING → CHANGE → IDLE // Test each valid transition AND invalid transitions // Valid: IDLE → insert coin → AWAITING_SELECTION // Valid: AWAITING_SELECTION → select item → DISPENSING // Invalid: AWAITING_SELECTION → select item (out of stock) → IDLE (refund) // Boundary values: // Amount = 0 → reject, stay IDLE // Amount = item price → dispense, 0 change // Amount = INT_MAX → overflow protection
// Test categories by risk: // CRITICAL (P0): Email actually sends and delivers // HIGH (P1): Attachments, Reply-all, Draft save // MEDIUM (P2): Formatting, CC/BCC, Undo send // LOW (P3): Keyboard shortcuts, theme, font size
// Test data strategy for Maps testing: // Use fixed start/end coordinates for reproducible tests // Real locations that have known routes // Test routes with known complexities (ferry, toll, highway) // Compare against known-correct directions as baseline
// Mobile-specific test scenarios to always include: // 1. App state after phone call interruption // 2. Low battery mode behavior // 3. Low storage (< 100MB free) // 4. Background/foreground app switching // 5. Different Android versions (5, 8, 10, 13, 14) // 6. Manufacturer-specific OS modifications (Samsung, OnePlus) // 7. Accessibility services: TalkBack enabled
// API test design checklist: // ✅ Authentication: valid token, expired, no token, wrong scope // ✅ Authorization: owner, editor, viewer, no access // ✅ Happy path: minimal valid request // ✅ Required fields: remove each required field // ✅ Optional fields: test with/without each // ✅ Boundary values: min, max, just over // ✅ Idempotency: same request twice // ✅ Error messages: correct status codes // ✅ Response time: meets SLA
// OAuth 2.0 security test assertions: // ✅ state param: random UUID per request, validated on return // ✅ code: single-use (second use returns 400) // ✅ redirect_uri: exact match with registered URIs // ✅ tokens: HTTPS only, never in GET params // ✅ logout: both access + refresh tokens revoked // ✅ JWT: signature verified, claims validated (exp, iss, aud)
// k6 load test script for Google API
import http from "k6/http";
import { check, sleep } from "k6";
export let options = {
stages: [
{ duration: "5m", target: 500 }, // ramp up
{ duration: "20m", target: 3000 }, // steady state
{ duration: "5m", target: 0 }, // ramp down
],
thresholds: {
"http_req_duration": ["p(99)<200"], // SLA
"http_req_failed": ["rate<0.0001"], // 0.01% error
},
};
export default function() {
let res = http.get("https://api.google.com/v1/endpoint",
{ headers: { "Authorization": `Bearer ${__ENV.TOKEN}` }});
check(res, { "status 200": r => r.status === 200 });
sleep(0.1);
} // Selenium + axe-core automated accessibility test
@Test
public void accessibilityTest_CheckoutPage_ShouldPassWCAG_AA() {
driver.get(BASE_URL + "/checkout");
// Inject axe-core and run accessibility check
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript(loadAxeScript()); // load axe-core JS
Map<String, Object> result = (Map<String, Object>)
js.executeScript("return axe.run()");
List<Map> violations = (List<Map>) result.get("violations");
violations.forEach(v -> System.out.println(
"VIOLATION: " + v.get("id") + " - " + v.get("description")));
Assert.assertEquals(violations.size(), 0,
"Accessibility violations found: " + violations.size());
} // Visual regression test with Playwright
const { test, expect } = require("@playwright/test");
test("Google Docs editor - visual regression", async ({ page }) => {
await page.goto("/docs/create");
await page.waitForLoadState("networkidle");
// Take full-page screenshot
await expect(page).toHaveScreenshot("docs-editor.png", {
fullPage: true,
animations: "disabled", // disable CSS animations
mask: [page.locator(".timestamp")], // mask dynamic content
});
});
// Playwright stores baseline on first run
// Subsequent runs diff against baseline
// toHaveScreenshot fails if diff > threshold 🌟 Googliness / Behavioral
Google evaluates "Googliness": intellectual humility, enjoying learning, doing the right thing, comfort with ambiguity. Less scripted than Amazon's LP round — more conversational. Focus on genuine stories, intellectual honesty, and curiosity over prepared scripts.
// My learning framework: // 1. Read official docs end-to-end (not tutorials) // 2. Build something real, not hello-world // 3. Find edge cases where documentation is unclear // 4. Join the community (Discord, GitHub issues) // 5. Teach someone else within 2 weeks (solidifies understanding) // 6. Document what surprised you (for the team)
// Signs of intellectual honesty Google looks for: // ✅ "I was wrong about X because Y" // ✅ "The data convinced me to change my approach" // ✅ "I held X belief until I saw evidence of Y" // ✅ "I tried to disprove my own hypothesis" // Signs of intellectual dishonesty (avoid): // ❌ "I was always right about this" // ❌ "I changed my mind because my manager told me to" // ❌ "I never make technical mistakes"
// Framework for testing under ambiguity: // 1. Interview stakeholders: "What does success look like?" // 2. Define your own testable acceptance criteria // 3. Start with what you DO know and expand // 4. Make your assumptions explicit and visible // 5. Build quick feedback loop (not perfect, but running) // 6. Iterate — refine criteria as you learn more // 7. Document your assumptions for team alignment
// Collaboration framework: // Before: "This team is difficult" // Reframe: "What is their incentive structure?" // "What do they find painful about our interaction?" // "What can I change in MY behavior?" // Common root causes of cross-team friction: // 1. Different definitions of "done" // 2. Bugs filed without sufficient context // 3. QA blocking releases for low-priority issues // 4. Dev not including QA in design reviews // Solution: always address the SYSTEM not the person
// Quantifiable impact metrics to have ready: // Test execution time: X hours → Y minutes (Z% reduction) // Release frequency: every N weeks → every M days // Bug escape rate: X% → Y% (defects caught before prod) // Test coverage: X% → Y% // Manual testing hours saved per sprint: N hours // Business impact: N releases per quarter vs previous M
// Failure story structure: // 1. What exactly went wrong (be specific, no vagueness) // 2. What was YOUR role (take full ownership) // 3. What was the impact (user/business impact in numbers) // 4. Root cause (your actual thinking error, not external factors) // 5. What changed in the SYSTEM (not just "I was more careful") // 6. Evidence the change worked (follow-up result)
// Quality strategy document outline: // 1. Risk register: top 10 risks + mitigation // 2. Quality goals: SLAs per metric // 3. Test pyramid: % allocation per layer // 4. Coverage map: critical user journeys vs test coverage // 5. Monitoring strategy: what gets alerted, who responds // 6. Release criteria: definition of "ready to ship" // 7. Chaos engineering plan: what do we intentionally break?
// Mentoring activities (pick 2-3 with specific outcomes): // 1. Pair testing: "Improved junior SDET's bug report quality, // acceptance rate went from 50% to 90%" // 2. Framework training: "Created 3-session workshop, // 2 juniors independently built page objects after" // 3. PR reviews: "Detailed review comments, junior started catching // their own XPath fragility issues after 4 reviews" // 4. Study group: "Ran weekly Java deep-dive, whole team passed // ISTQB Foundation in Q3"
// Process improvement template: // PROBLEM: specific pain point with data // "It took 40 min to understand someone else's test case" // ROOT CAUSE: why is it happening? // "No standard format, everyone writes differently" // SOLUTION: what specifically you built/changed // ADOPTION: how you got others to follow it // RESULT: measurable improvement (time, quality, velocity) // Key: "I initiated" not "I suggested" // Show you drove it to completion, not just proposed
// Prioritization framework: // P1: Customer/quality impact, deadline TODAY // P2: Customer/quality impact, deadline THIS WEEK // P3: Important but deadline flexible // P4: Nice to have // "Urgent important" matrix: // High impact + high urgency → do now // High impact + low urgency → schedule block // Low impact + high urgency → delegate or quick-fix // Low impact + low urgency → decline or backlog // Communication rule: raise a capacity concern // when it's still 3 days early, not 1 hour before deadline
Microsoft Interview Process
FAANG · Azure · Office · Teams · Redmond USA · 4–5 Rounds
☕ Technical Round 1
Microsoft technical rounds for SDET focus on Java OOP design quality, SOLID principles, and clean code. They care about code readability and maintainability as much as correctness. Expect "write a mini-system" style questions.
public abstract class ParkingSpot {
protected String id; protected boolean isOccupied;
public abstract VehicleType getType();
public boolean canFit(Vehicle v) { return v.getType() == getType(); }
public void park(Vehicle v) { isOccupied = true; }
public void unpark() { isOccupied = false; }
}
public class ParkingFloor {
private List<ParkingSpot> spots;
public Optional<ParkingSpot> findAvailableSpot(Vehicle v) {
return spots.stream()
.filter(s -> !s.isOccupied && s.canFit(v)).findFirst();
}
}
public class ParkingLot {
private List<ParkingFloor> floors;
private Map<String, ParkingTicket> tickets = new HashMap<>();
public ParkingTicket park(Vehicle v) {
for (ParkingFloor f : floors) {
Optional<ParkingSpot> spot = f.findAvailableSpot(v);
if (spot.isPresent()) {
spot.get().park(v);
ParkingTicket t = new ParkingTicket(spot.get().id);
tickets.put(t.id, t); return t;
}
}
throw new ParkingFullException("No available spot");
}
} // Thread-safe Singleton (double-checked locking)
public class ConfigReader {
private static volatile ConfigReader instance;
private Properties props;
private ConfigReader() {
props = new Properties();
try { props.load(getClass().getResourceAsStream("/config.properties")); }
catch (IOException e) { throw new RuntimeException(e); }
}
public static ConfigReader getInstance() {
if (instance == null) {
synchronized (ConfigReader.class) {
if (instance == null) instance = new ConfigReader();
}
}
return instance;
}
public String get(String key) { return props.getProperty(key); }
}
// Usage: ConfigReader.getInstance().get("base.url") public class DriverFactory {
public static WebDriver createDriver(String browser) {
return switch (browser.toLowerCase()) {
case "chrome" -> { ChromeOptions o = new ChromeOptions();
o.addArguments("--headless=new");
yield new ChromeDriver(o); }
case "firefox" -> { FirefoxOptions o = new FirefoxOptions();
o.addArguments("-headless");
yield new FirefoxDriver(o); }
case "edge" -> new EdgeDriver();
case "remote" -> {
String gridUrl = ConfigReader.getInstance().get("grid.url");
ChromeOptions o = new ChromeOptions();
yield new RemoteWebDriver(new URL(gridUrl), o);
}
default -> throw new IllegalArgumentException("Unknown browser: "+browser);
};
}
}
// Usage: WebDriver d = DriverFactory.createDriver(System.getProperty("browser","chrome")); // Root exception for framework
public class AutomationException extends RuntimeException {
private final ErrorCode code;
public AutomationException(ErrorCode code, String msg) { super(msg); this.code=code; }
public AutomationException(ErrorCode code, String msg, Throwable cause) {
super(msg, cause); this.code=code;
}
public ErrorCode getCode() { return code; }
}
public enum ErrorCode { ELEMENT_NOT_FOUND, PAGE_LOAD_TIMEOUT, API_ERROR, DATA_ERROR }
// Specific exceptions
public class ElementNotFoundException extends AutomationException {
public ElementNotFoundException(By locator) {
super(ErrorCode.ELEMENT_NOT_FOUND,
"Element not found: " + locator.toString());
}
}
public class PageLoadTimeoutException extends AutomationException {
public PageLoadTimeoutException(String page, int timeoutSec) {
super(ErrorCode.PAGE_LOAD_TIMEOUT,
page + " did not load within " + timeoutSec + "s");
}
}
// In BasePage:
protected WebElement findElement(By by) {
try { return wait.until(ExpectedConditions.visibilityOfElementLocated(by)); }
catch (TimeoutException e) { throw new ElementNotFoundException(by); }
} // Before: God class (anti-pattern)
public class TestHelper {
public WebElement waitForElement(By by) {...}
public void clickElement(By by) {...}
public void scrollToElement(WebElement el) {...}
// ... 47 more mixed methods
public String readExcel(String file, int row) {...}
public void logTestStart(String name) {...}
public String getApiToken() {...}
public Response sendApiRequest(String url) {...}
}
// After: Single Responsibility (each class does ONE thing)
public class ElementActions { // UI interactions only
public void click(By by) {...}
public void type(By by, String text) {...}
public WebElement waitFor(By by) {...}
}
public class BrowserUtils { // browser-level operations
public void scrollTo(WebElement el) {...}
public void switchToFrame(By by) {...}
public byte[] takeScreenshot() {...}
}
public class ExcelReader { // data utilities only
public String readCell(String file, int row, int col) {...}
public Object[][] readSheet(String file) {...}
}
public class ApiClient { // API calls only
public Response get(String endpoint) {...}
public Response post(String endpoint, Object body) {...}
} // Strategy interface
public interface ReportStrategy {
void startTest(String name, String description);
void logStep(String stepName, boolean passed);
void attachScreenshot(byte[] screenshot);
void endTest(boolean passed);
void generateReport();
}
// Allure implementation
public class AllureReporter implements ReportStrategy {
@Override
public void startTest(String name, String description) {
Allure.description(description);
}
@Override @Attachment(value="Screenshot", type="image/png")
public void attachScreenshot(byte[] img) { ... }
// ...
}
// Extent implementation
public class ExtentReporter implements ReportStrategy {
private ExtentTest test;
@Override
public void startTest(String name, String description) {
test = ExtentReports.getInstance().createTest(name, description);
}
// ...
}
// Factory to select reporter
public class ReportFactory {
public static ReportStrategy create() {
return switch(Config.get("reporter")) {
case "allure" -> new AllureReporter();
case "extent" -> new ExtentReporter();
default -> new HtmlReporter();
};
}
} public class PageFactory {
private WebDriver driver;
public PageFactory(WebDriver driver) { this.driver = driver; }
public <T extends BasePage> T create(Class<T> pageClass) {
try {
T page = pageClass.getDeclaredConstructor(WebDriver.class)
.newInstance(driver);
org.openqa.selenium.support.PageFactory.initElements(driver, page);
return page;
} catch (Exception e) {
throw new AutomationException(ErrorCode.PAGE_INIT_FAILED,
"Could not create page: " + pageClass.getSimpleName(), e);
}
}
}
// Usage (type-safe, no casting needed):
PageFactory factory = new PageFactory(driver);
LoginPage login = factory.create(LoginPage.class);
DashboardPage dash = factory.create(DashboardPage.class);
// Fluent builder chain:
factory.create(LoginPage.class)
.enterEmail("user@test.com")
.enterPassword("pass")
.clickLogin()
.verifyDashboardVisible(); // Thread-safe result collection for parallel tests
public class TestResultCollector {
// ConcurrentHashMap: thread-safe reads/writes per key
private final Map<String, TestResult> results = new ConcurrentHashMap<>();
// CopyOnWriteArrayList: thread-safe iteration even during writes
private final List<String> failedTests = new CopyOnWriteArrayList<>();
public void recordResult(String testId, boolean passed, long durationMs) {
results.put(testId, new TestResult(testId, passed, durationMs));
if (!passed) failedTests.add(testId);
}
public void printSummary() {
int total = results.size();
int passed = (int) results.values().stream().filter(r->r.passed).count();
int failed = failedTests.size();
double rate = (double) passed / total * 100;
System.out.printf("Total: %d | Passed: %d | Failed: %d | Rate: %.1f%%",
total, passed, failed, rate);
}
}
// AtomicInteger for thread-safe counters
private final AtomicInteger passCount = new AtomicInteger(0);
// passCount.incrementAndGet(); // thread-safe increment public class UserTestData {
private final String email, password, firstName, lastName, role;
private final boolean isVerified, isActive;
private final String phoneNumber, address;
private UserTestData(Builder b) {
this.email = b.email; this.password = b.password;
this.firstName = b.firstName; this.lastName = b.lastName;
this.role = b.role; this.isVerified= b.isVerified;
this.isActive = b.isActive;
this.phoneNumber = b.phoneNumber; this.address = b.address;
}
public static class Builder {
// Required fields
private String email, password;
// Optional fields with defaults
private String firstName="Test", lastName="User", role="USER";
private boolean isVerified=true, isActive=true;
private String phoneNumber, address;
public Builder(String email, String password) {
this.email=email; this.password=password;
}
public Builder role(String r) { this.role=r; return this; }
public Builder verified(boolean v) { isVerified=v; return this; }
public Builder phone(String p) { this.phoneNumber=p; return this; }
public UserTestData build() { return new UserTestData(this); }
}
}
// Usage:
UserTestData admin = new UserTestData.Builder("a@t.com","pass")
.role("ADMIN").verified(true).phone("9999999999").build();
UserTestData unverified = new UserTestData.Builder("b@t.com","pass")
.verified(false).build(); // Before ISP violation: one large interface
interface IPage {
void clickElement(By by); // all pages need
void fillForm(Map data); // only form pages need
void verifyChart(String id); // only dashboard pages need
void uploadFile(By by, String path); // only upload pages need
}
// After ISP: focused interfaces
interface IClickable { void click(By by); void hover(By by); }
interface IFormFillable{ void fill(Map<String,String> data); void submit(); }
interface IVerifiable { boolean isVisible(By by); String getText(By by); }
interface IFileUploader{ void upload(By by, String filePath); }
// Each page implements only what it needs:
class LoginPage extends BasePage implements IClickable, IFormFillable {
// No uploadFile or verifyChart methods imposed
}
class UploadPage extends BasePage implements IClickable, IFileUploader {
// No fillForm methods imposed
}
class DashboardPage extends BasePage implements IVerifiable, IClickable {
// All analytics-specific methods only
} 🏗️ Design Round
Microsoft Design round: design testing strategy for a Microsoft product (Teams, Azure, Office, Xbox). They evaluate your ability to think at system scale, identify risk, and design for observability. Always start: "Let me clarify the scope."
// Test Design for Teams message delivery: // Risk 1: Message not delivered (HIGH) → E2E delivery verification // Risk 2: Message order wrong (HIGH) → timestamp ordering tests // Risk 3: Message not encrypted (CRITICAL) → security tests // Risk 4: Mentions/notifications fail (MEDIUM) → @mention tests // Risk 5: Offline sync failure (MEDIUM) → reconnect tests
// Azure DevOps Pipeline (yaml)
stages:
- stage: Test
jobs:
- job: UnitTests
steps:
- task: Maven@3
inputs: { goals: "test jacoco:report", options: "-Dgroups=unit" }
- task: PublishCodeCoverageResults@1
- job: ContractTests
dependsOn: UnitTests
steps:
- script: mvn test -Dgroups=contract
- job: IntegrationTests
dependsOn: ContractTests
steps:
- script: mvn test -Dgroups=integration -Denv=dev
- stage: PerformanceGate
dependsOn: Test
jobs:
- job: PerfBaseline
steps:
- script: k6 run --env ENV=staging tests/perf.js
env: { K6_CLOUD_TOKEN: $(K6_TOKEN) } // OneDrive sync performance test approach: // Use: Microsoft Graph API to upload files programmatically // Measure: time from API upload to file appearing on sync client // Tool: k6 for API load, PowerShell for sync client automation // Key metric: Delta Sync (only changed bytes sent, not full file) // Test: modify 1 byte in 1GB file // Expected: only 1KB delta transmitted, not 1GB retransmission
// AAD Security Test Cases:
@Test public void bruteForce_ShouldLockAfter5Attempts() {
for (int i = 0; i < 4; i++)
given().body(invalidCreds).post("/login").then().statusCode(401);
// 5th attempt → locked
given().body(invalidCreds).post("/login").then().statusCode(423); // Locked
}
@Test public void crossTenant_ShouldReturn403() {
String tenantAToken = getToken("tenantA");
given().header("Authorization", "Bearer " + tenantAToken)
.get("/tenants/tenantB/users")
.then().statusCode(403);
} // Axe-core accessibility test in Selenium
@Test
public void teamsLogin_ShouldPassWCAG_AA() {
driver.get(TEAMS_URL + "/login");
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript(axeScript);
@SuppressWarnings("unchecked")
Map<String,Object> res = (Map<String,Object>) js.executeScript(
"return axe.run({ runOnly: { type: \"tag\", values: [\"wcag2aa\"] } })");
List violations = (List) res.get("violations");
Assert.assertEquals(violations.size(), 0,
"WCAG AA violations: " + violations.size());
} public class TenantFactory {
public static TestTenant createEphemeral() {
String tenantId = "test-" + UUID.randomUUID();
given()
.header("Authorization", "Bearer " + getAdminToken())
.body(Map.of("tenantId", tenantId, "tier", "TRIAL"))
.post("/admin/tenants")
.then().statusCode(201);
return new TestTenant(tenantId);
}
public static void cleanup(TestTenant tenant) {
given()
.header("Authorization", "Bearer " + getAdminToken())
.delete("/admin/tenants/" + tenant.id)
.then().statusCode(204);
}
}
// In test:
@BeforeMethod void setUp() { tenant = TenantFactory.createEphemeral(); }
@AfterMethod void tearDown() { TenantFactory.cleanup(tenant); } // Azure Chaos Studio experiment (JSON config)
{
"steps": [{
"name": "Step1-RegionFailover",
"branches": [{
"name": "Kill primary region network",
"actions": [{
"type": "continuous",
"name": "NSFW-1",
"duration": "PT10M",
"parameters": { "virtualMachineScaleSetId": "/subscriptions/.../vmss" }
}]
}]
}],
"startOnCreation": false
}
// Monitor: Azure Monitor alerts + custom SLA dashboard
// Abort condition: error rate > 1% triggers auto-stop // Provider verification in CI pipeline
@Provider("UserService")
@PactBroker(host="pactbroker.company.com",
authentication=@PactBrokerAuth(token="${PACT_TOKEN}"))
@ExtendWith(PactVerificationInvocationContextProvider.class)
public class UserServiceProviderTest {
@TestTemplate
@ExtendWith(PactVerificationInvocationContextProvider.class)
void verifyPact(PactVerificationContext context) {
context.verifyInteraction();
}
@BeforeEach
void setUp(PactVerificationContext context) {
context.setTarget(new HttpTestTarget(
testServer.getHost(), testServer.getPort()));
}
// State setup for each consumer expectation
@State("user 123 exists")
public void userExists() {
userRepo.save(new User("123", "test@email.com", "Test User"));
}
} // Rich test observability in BaseTest
public class BaseTest {
@BeforeMethod
public void enableObservability() {
driver.executeCdpCommand("Network.enable", Map.of());
driver.executeCdpCommand("Console.enable", Map.of());
networkLogs = new ArrayList<>();
// Capture every network request
driver.addDevToolsEventListener("Network.requestWillBeSent",
e -> networkLogs.add(e.get("request")));
}
@AfterMethod(alwaysRun = true)
public void collectDiagnostics(ITestResult result) {
if (!result.isSuccess()) {
Allure.addAttachment("Screenshot", "image/png",
new ByteArrayInputStream(takeScreenshot()), "png");
Allure.addAttachment("NetworkLog", "text/json",
networkLogs.toString());
Allure.addAttachment("BrowserConsole", "text/plain",
getBrowserLogs());
}
}
} // Surface Duo specific test tooling: // Microsoft Surface Duo Emulator (available in Android Studio) // SurfaceDuoHelper API: // isDualScreenMode() → boolean // getHingeAngle() → 0-360 // getSpannedRect() → left+right screen bounds // Appium dual-screen automation: // Use Microsoft Windows Application Driver (WinAppDriver) // Extended with SurfaceDuo specific capabilities // "microsoft:surfaceHingeAngle": 90 // 90 degree hinge
Flipkart Interview Process
Indian Product · E-Commerce · Walmart-owned · Bangalore HQ · 4–5 Rounds
💻 Coding Test (HackerEarth)
Flipkart's OA is 90 minutes with 2–3 coding problems. Strong Java skills required. They read code for QUALITY not just correctness. Write clean, well-named variables and include edge case handling.
public List<List<String>> groupAnagrams(String[] strs) {
Map<String,List<String>> map = new HashMap<>();
for (String s : strs) {
char[] c = s.toCharArray(); Arrays.sort(c);
map.computeIfAbsent(new String(c), k->new ArrayList<>()).add(s);
}
return new ArrayList<>(map.values());
}
// ["eat","tea","tan","ate","nat","bat"]
// → [["eat","tea","ate"],["tan","nat"],["bat"]] public int firstUniqChar(String s) {
int[] freq = new int[26];
for (char c : s.toCharArray()) freq[c-"a"]++;
for (int i = 0; i < s.length(); i++)
if (freq[s.charAt(i)-"a"] == 1) return i;
return -1;
}
// "leetcode"→0 "loveleetcode"→2 "aabb"→-1 public List<String> permutations(String s) {
List<String> result = new ArrayList<>();
char[] arr = s.toCharArray();
permute(arr, 0, result);
return result;
}
private void permute(char[] arr, int start, List<String> res) {
if (start == arr.length) { res.add(new String(arr)); return; }
for (int i = start; i < arr.length; i++) {
swap(arr, start, i);
permute(arr, start+1, res);
swap(arr, start, i); // backtrack
}
}
private void swap(char[] a, int i, int j) { char t=a[i]; a[i]=a[j]; a[j]=t; }
// "abc" → ["abc","acb","bac","bca","cab","cba"] public int maxProduct(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
// Compare: product of two largest vs two most negative
return Math.max(nums[n-1]*nums[n-2], nums[0]*nums[1]);
}
// [-4,-3,2,6] → 12 ((-4)*(-3))
// [1,2,3,4] → 12 (3*4) public int evalRPN(String[] tokens) {
Deque<Integer> stack = new ArrayDeque<>();
for (String t : tokens) {
switch(t) {
case "+" -> stack.push(stack.pop() + stack.pop());
case "-" -> { int b=stack.pop(),a=stack.pop(); stack.push(a-b); }
case "*" -> stack.push(stack.pop() * stack.pop());
case "/" -> { int b=stack.pop(),a=stack.pop(); stack.push(a/b); }
default -> stack.push(Integer.parseInt(t));
}
}
return stack.pop();
}
// ["2","1","+","3","*"] → 9 (2+1=3, 3*3=9) public int findMin(int[] nums) {
int lo = 0, hi = nums.length - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (nums[mid] > nums[hi]) lo = mid + 1; // min in right
else hi = mid; // min in left (or is mid)
}
return nums[lo];
}
// [3,4,5,1,2] → 1 [4,5,6,7,0,1,2] → 0 [1] → 1 public double myPow(double x, int n) {
long N = n; // handle Integer.MIN_VALUE
if (N < 0) { x = 1/x; N = -N; }
double result = 1.0;
while (N > 0) {
if (N % 2 == 1) result *= x;
x *= x;
N /= 2;
}
return result;
}
// 2.0^10=1024.0 2.0^-2=0.25 0^0=1 public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
// First row and column: only one way to reach
for (int i=0;i<m;i++) dp[i][0]=1;
for (int j=0;j<n;j++) dp[0][j]=1;
for (int i=1;i<m;i++)
for (int j=1;j<n;j++)
dp[i][j] = dp[i-1][j] + dp[i][j-1];
return dp[m-1][n-1];
}
// 3x7 grid → 28 unique paths
// O(1) space solution: C(m+n-2, m-1) combinations formula public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) return root; // LCA found
return left != null ? left : right;
}
// If both found in different subtrees → root is LCA
// If one is null → LCA is in the non-null subtree public boolean canFinish(int numCourses, int[][] prerequisites) {
List<List<Integer>> adj = new ArrayList<>();
for (int i=0;i<numCourses;i++) adj.add(new ArrayList<>());
for (int[] p : prerequisites) adj.get(p[1]).add(p[0]);
int[] visited = new int[numCourses]; // 0=unvisited 1=visiting 2=done
for (int i=0;i<numCourses;i++)
if (visited[i]==0 && hasCycle(adj, visited, i)) return false;
return true;
}
private boolean hasCycle(List<List<Integer>> adj, int[] vis, int node) {
vis[node] = 1; // currently visiting
for (int next : adj.get(node)) {
if (vis[next]==1) return true; // back edge = cycle
if (vis[next]==0 && hasCycle(adj, vis, next)) return true;
}
vis[node] = 2; // done
return false;
}
// [[1,0],[0,1]] → false (cycle: 0→1→0) [[1,0]] → true 🔬 Technical Round 1
Flipkart Tech Round 1 goes deep on Java OOP, Selenium internals, and your actual framework. The interviewer reads your resume and asks specifics about every project you mention. Be ready to justify every design decision.
// BasePage.java
public class BasePage {
protected WebDriver driver;
protected WebDriverWait wait;
public BasePage(WebDriver d) {
this.driver=d; this.wait=new WebDriverWait(d, Duration.ofSeconds(15));
PageFactory.initElements(d, this);
}
protected void click(By by) {
wait.until(ExpectedConditions.elementToBeClickable(by)).click();
}
protected String getText(By by) {
return wait.until(ExpectedConditions.visibilityOfElementLocated(by)).getText();
}
}
// CartPage.java
public class CartPage extends BasePage {
@FindBy(css=".cart-item") private List<WebElement> items;
@FindBy(id="proceed-to-buy") private WebElement proceedBtn;
public CartPage(WebDriver d) { super(d); }
public int getItemCount() { return items.size(); }
public CheckoutPage proceedToBuy() { proceedBtn.click(); return new CheckoutPage(driver); }
} public class DriverFactory {
private static final ThreadLocal<WebDriver> pool = new ThreadLocal<>();
public static WebDriver get() { return pool.get(); }
public static void init(String browser) {
WebDriver d = switch(browser) {
case "firefox" -> new FirefoxDriver();
default -> { ChromeOptions o=new ChromeOptions();
o.addArguments("--headless=new","--no-sandbox");
yield new ChromeDriver(o); }
};
d.manage().window().maximize();
pool.set(d);
}
public static void quit() {
if (pool.get()!=null) { pool.get().quit(); pool.remove(); } // CRITICAL
}
} // Product card by title containing text
By.xpath("//div[contains(@class,\"_1AtVbE\")]//a[contains(text(),\"iPhone\")]")
// Product card by position (3rd result)
By.xpath("(//div[@data-id and contains(@class,\"_13oc-S\")])[3]")
// Product price using sibling navigation
By.xpath("//div[contains(text(),\"iPhone\")]/../../..//div[@class=\"_30jeq3\"]")
// Better - use data attributes (more stable):
By.cssSelector("[data-id][data-tkid]")
// Dynamic attribute with partial match:
By.xpath("//button[contains(@class,\"_2KpZ6l\") and @type=\"button\"]")
// Text contains partial match:
By.xpath("//*[contains(translate(text(),\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\"abcdefghijklmnopqrstuvwxyz\"),\"add to cart\")]") // Wait for AJAX to complete (jQuery approach)
public void waitForAjax() {
wait.until(d -> ((JavascriptExecutor)d)
.executeScript("return jQuery.active==0").equals(true));
}
// Wait for network idle via CDP (Selenium 4)
public void waitForNetworkIdle() {
Map<String,Object> params = new HashMap<>();
params.put("timeout", 10000);
driver.executeCdpCommand("Page.waitForNetworkIdle", params);
}
// Wait for Angular app ready
public void waitForAngular() {
String angularReady = "return window.getAllAngularTestabilities()"+
".every(t => t.isStable())";
wait.until(d -> ((JavascriptExecutor)d)
.executeScript(angularReady).equals(true));
}
// Always prefer: wait for specific element visible
wait.until(ExpectedConditions.visibilityOf(productList)); public class WaitHelper {
private final WebDriverWait wait;
private static final int DEFAULT_TIMEOUT =
Integer.parseInt(Config.get("wait.timeout.seconds", "15"));
public WaitHelper(WebDriver driver) {
this(driver, DEFAULT_TIMEOUT);
}
public WaitHelper(WebDriver driver, int timeoutSec) {
this.wait = new WebDriverWait(driver, Duration.ofSeconds(timeoutSec));
}
public WebElement forVisible(By by) {
return wait.until(ExpectedConditions.visibilityOfElementLocated(by));
}
public WebElement forClickable(By by) {
return wait.until(ExpectedConditions.elementToBeClickable(by));
}
public boolean forTextPresent(By by, String text) {
return wait.until(ExpectedConditions.textToBePresentInElementLocated(by, text));
}
public void forUrlContains(String urlPart) {
wait.until(ExpectedConditions.urlContains(urlPart));
}
}
// config.properties:
// wait.timeout.seconds=15 (staging)
// wait.timeout.seconds=5 (dev - faster machines) // Method 1: Selenium 4 DevTools (full page)
public byte[] takeFullPageScreenshot() {
DevTools dt = ((HasDevTools) driver).getDevTools();
dt.createSession();
Optional<Page.CaptureScreenshotResponse> resp =
dt.send(Page.captureScreenshot(
Optional.of(Page.CaptureScreenshotFormat.PNG),
Optional.empty(), Optional.empty(),
Optional.of(true), // captureBeyondViewport = true
Optional.empty()));
return Base64.getDecoder().decode(resp.get().getData());
}
// Method 2: Scroll and stitch (fallback)
public void scrollAndCapture(String filename) throws Exception {
JavascriptExecutor js = (JavascriptExecutor) driver;
long totalHeight = (long) js.executeScript("return document.body.scrollHeight");
long viewHeight = (long) js.executeScript("return window.innerHeight");
long scrollY = 0;
List<BufferedImage> parts = new ArrayList<>();
while (scrollY < totalHeight) {
js.executeScript("window.scrollTo(0," + scrollY + ")");
Thread.sleep(200); // wait for scroll
parts.add(ImageIO.read(((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE)));
scrollY += viewHeight;
}
// stitch parts into one image...
} # .github/workflows/test.yml
name: Selenium Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { java-version: "17" }
- name: Run Tests
run: mvn test -Dgroups=regression -Dbrowser=chrome
continue-on-error: true # collect results even on failure
- name: Generate Allure Report
uses: simple-elf/allure-report-action@master
with:
allure_results: target/allure-results
allure_history: allure-history
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: allure-history
- name: Post PR Comment with Report Link
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({ issue_number: context.issue.number,
owner: context.repo.owner, repo: context.repo.repo,
body: "📊 Allure Report: https://"+context.repo.owner+".github.io/"+context.repo.repo }) @SuppressWarnings("unused")
public class QAListener implements ITestListener, ISuiteListener {
private final Map<String,Long> startTimes = new ConcurrentHashMap<>();
@Override public void onTestStart(ITestResult r) {
startTimes.put(r.getName(), System.currentTimeMillis());
Allure.step("Test started: " + r.getName());
}
@Override public void onTestFailure(ITestResult r) {
// Screenshot attachment
byte[] screenshot = ((TakesScreenshot)DriverFactory.get())
.getScreenshotAs(OutputType.BYTES);
Allure.addAttachment("Failure Screenshot","image/png",
new ByteArrayInputStream(screenshot), "png");
// Duration logging
long duration = System.currentTimeMillis() - startTimes.get(r.getName());
System.err.printf("[FAIL] %s — %dms%n", r.getName(), duration);
}
@Override public void onFinish(ISuite suite) {
// Suite summary stats
int passed=0, failed=0;
for(ISuiteResult r : suite.getResults().values()) {
passed += r.getTestContext().getPassedTests().size();
failed += r.getTestContext().getFailedTests().size();
}
// Slack notification
SlackNotifier.send(String.format("Suite: %s | P:%d F:%d | %s",
suite.getName(), passed, failed, failed==0?"✅":"❌"));
}
} # docker-compose.yml for Selenium Grid 4
version: "3"
services:
selenium-hub:
image: selenium/hub:4.18.1
ports: [ "4444:4444","4442:4442","4443:4443" ]
environment:
SE_NODE_MAX_SESSIONS: "5"
SE_SESSION_TIMEOUT: "60"
chrome-node:
image: selenium/node-chrome:4.18.1
depends_on: [selenium-hub]
environment:
SE_EVENT_BUS_HOST: selenium-hub
SE_EVENT_BUS_PUBLISH_PORT: "4442"
SE_EVENT_BUS_SUBSCRIBE_PORT: "4443"
SE_NODE_MAX_SESSIONS: "3"
scale: 3 # 3 Chrome nodes = 9 parallel Chrome sessions
firefox-node:
image: selenium/node-firefox:4.18.1
depends_on: [selenium-hub]
environment:
SE_EVENT_BUS_HOST: selenium-hub
scale: 2
# In DriverFactory: use RemoteWebDriver
// WebDriver d = new RemoteWebDriver(new URL("http://localhost:4444"), opts); @Test
public void searchAPI_WithFilters_ShouldReturnFilteredResults() {
given()
.baseUri(BASE_URL)
.queryParam("q", "laptop")
.queryParam("brand", "Apple")
.queryParam("minPrice", 50000)
.queryParam("maxPrice", 150000)
.queryParam("rating", 4)
.queryParam("page", 1)
.queryParam("size", 20)
.when()
.get("/search")
.then()
.statusCode(200)
.time(lessThan(500L)) // SLA
.body("results.size()", lessThanOrEqualTo(20))
.body("results.every { it.brand == \"Apple\" }", is(true))
.body("results.every { it.price >= 50000 }", is(true))
.body("results.every { it.price <= 150000 }", is(true))
.body("results.every { it.rating >= 4.0 }", is(true))
.body("pagination.page", equalTo(1))
.body("pagination.totalPages", greaterThan(0));
}
@Test public void searchAPI_EmptyQuery_ShouldReturn400() {
given().baseUri(BASE_URL).queryParam("q", "")
.when().get("/search").then().statusCode(400);
} TCS Interview Process
IT Services · MNC · Largest Indian IT Company · Pan-India + Global · 3–4 Rounds
📝 TCS NQT / Online Test
TCS NQT has 4 sections: Aptitude (30 min), Reasoning (25 min), Verbal (30 min), Coding (45 min — 2 problems). For QA roles, TCS Prime has additional domain-specific questions. Coding problems are Easy to Medium.
public String reverseWords(String s) {
String[] words = s.trim().split("\s+");
StringBuilder sb = new StringBuilder();
for (int i=words.length-1;i>=0;i--) {
sb.append(words[i]);
if (i>0) sb.append(" ");
}
return sb.toString();
}
// "Hello World Java" → "Java World Hello"
// " spaces here " → "here spaces" public boolean isArmstrong(int n) {
String s = String.valueOf(n);
int len = s.length();
int sum = 0;
for (char c : s.toCharArray())
sum += (int) Math.pow(c - "0", len);
return sum == n;
}
// 153 → true (1+125+27=153)
// 9474 → true (9^4+4^4+7^4+4^4=9474)
// 100 → false public int secondLargest(int[] arr) {
int max=Integer.MIN_VALUE, second=Integer.MIN_VALUE;
for (int n : arr) {
if (n > max) { second=max; max=n; }
else if (n>second && n!=max) second=n;
}
return second; // Integer.MIN_VALUE if no second distinct element
}
// [1,2,3,4,5] → 4 [5,5,5] → MIN_VALUE [1] → MIN_VALUE // Method 1: Sorting
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) return false;
char[] sc=s.toCharArray(), tc=t.toCharArray();
Arrays.sort(sc); Arrays.sort(tc);
return Arrays.equals(sc, tc);
}
// Method 2: Frequency (O(n) time, O(1) space)
public boolean isAnagram2(String s, String t) {
if (s.length()!=t.length()) return false;
int[] count=new int[26];
for (int i=0;i<s.length();i++) {
count[s.charAt(i)-"a"]++;
count[t.charAt(i)-"a"]--;
}
for (int c : count) if (c!=0) return false;
return true;
}
// "anagram","nagaram" → true "rat","car" → false // Iterative approach
public int addDigits(int num) {
while (num >= 10) {
int sum = 0;
while (num > 0) { sum += num % 10; num /= 10; }
num = sum;
}
return num;
}
// O(1) math formula:
public int addDigitsO1(int num) {
if (num==0) return 0;
return num%9==0 ? 9 : num%9;
}
// 38 → 3+8=11 → 1+1=2 → answer: 2
// 0 → 0 9 → 9 18 → 9 public List<int[]> findPairs(int[] arr, int target) {
List<int[]> pairs = new ArrayList<>();
Set<Integer> seen = new HashSet<>();
Set<String> used = new HashSet<>(); // avoid duplicate pairs
for (int n : arr) {
int complement = target - n;
if (seen.contains(complement)) {
String key = Math.min(n,complement)+","+Math.max(n,complement);
if (used.add(key))
pairs.add(new int[]{complement, n});
}
seen.add(n);
}
return pairs;
}
// [1,5,3,2,4] target=6 → [[1,5],[2,4],[3,3 only if duplicate]] // Recursive (for learning - exponential time)
public int fib(int n) {
if (n<=1) return n;
return fib(n-1) + fib(n-2);
}
// Memoized (efficient - O(n) time)
public int fibMemo(int n, int[] memo) {
if (n<=1) return n;
if (memo[n]!=-1) return memo[n];
return memo[n] = fibMemo(n-1,memo) + fibMemo(n-2,memo);
}
// Iterative (most efficient - O(1) space)
public int fibIter(int n) {
if (n<=1) return n;
int a=0, b=1;
for (int i=2;i<=n;i++) { int c=a+b; a=b; b=c; }
return b;
}
// 0,1,1,2,3,5,8,13,21,34,... public int[] countVowelsConsonants(String s) {
s = s.toLowerCase();
String vowels = "aeiou";
int vCount=0, cCount=0;
for (char c : s.toCharArray()) {
if (Character.isLetter(c)) {
if (vowels.indexOf(c) != -1) vCount++;
else cCount++;
}
}
return new int[]{vCount, cCount};
}
// "Hello World" → vowels=3, consonants=7
// "AEIOU" → vowels=5, consonants=0 // Recursive
public long factorialRec(int n) {
if (n<=1) return 1;
return n * factorialRec(n-1);
}
// Iterative
public long factorialIter(int n) {
long result = 1;
for (int i=2; i<=n; i++) result *= i;
return result;
}
// 5! = 120 10! = 3628800 0! = 1
// Edge cases to mention:
// n < 0: throw IllegalArgumentException
// n > 20: result overflows long — use BigInteger
public BigInteger factorialBig(int n) {
BigInteger result = BigInteger.ONE;
for (int i=2;i<=n;i++) result=result.multiply(BigInteger.valueOf(i));
return result;
} public void rotate(int[] nums, int k) {
k %= nums.length; // handle k > length
reverse(nums, 0, nums.length-1);
reverse(nums, 0, k-1);
reverse(nums, k, nums.length-1);
}
private void reverse(int[] arr, int lo, int hi) {
while (lo < hi) { int t=arr[lo]; arr[lo++]=arr[hi]; arr[hi--]=t; }
}
// [1,2,3,4,5,6,7] k=3 → [5,6,7,1,2,3,4]
// Steps: reverse all →[7,6,5,4,3,2,1]
// reverse first 3 →[5,6,7,4,3,2,1]
// reverse rest →[5,6,7,1,2,3,4] ✓ 🔬 Technical Interview
TCS technical interview for QA focuses on SDLC/STLC theory, testing types, Selenium basics, SQL for testers, and manual testing concepts. More knowledge-based than algorithmic. Be fluent in testing terminology.
// Timing: // Smoke Test → after every new build deployment // Sanity Test → after a specific bug fix // Regression → before every release // Who runs them: // Smoke → QA team (quick gate check) // Sanity → QA engineer who fixed the bug // Regression → QA team (automated suite) // Scope: // Smoke → broad, shallow (10-20% of features) // Sanity → narrow, deep (single feature) // Regression → broad, deep (all features)
// Entry and Exit criteria per phase: Phase | Entry Criteria | Exit Criteria Test Planning | SRS signed off | Test Plan document approved Test Design | Functional specs available | Test cases reviewed + approved Test Execution | Test environment ready | All P1/P2 bugs resolved Test Closure | All tests executed | Closure report signed // RTM = Requirements Traceability Matrix // Links: Requirement → Test Cases → Bugs found // Ensures every requirement has test coverage
public class LoginTest {
WebDriver driver;
@BeforeMethod public void setUp() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@Test public void validLogin_ShouldNavigateToDashboard() {
driver.get("https://example.com/login");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Enter credentials
driver.findElement(By.id("username")).sendKeys("testuser@email.com");
driver.findElement(By.id("password")).sendKeys("Password123");
driver.findElement(By.id("loginBtn")).click();
// Verify login success
wait.until(ExpectedConditions.urlContains("/dashboard"));
WebElement welcome = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("welcome-msg")));
Assert.assertTrue(welcome.isDisplayed(), "Welcome message not shown");
}
@AfterMethod public void tearDown() { if(driver!=null) driver.quit(); }
} -- Find customers with more than 3 recent orders
SELECT c.customer_id, c.name, COUNT(o.order_id) AS order_count
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_date >= CURDATE() - INTERVAL 30 DAY
AND o.status != "CANCELLED"
GROUP BY c.customer_id, c.name
HAVING COUNT(o.order_id) > 3
ORDER BY order_count DESC;
-- Related QA use case: validate this query in test automation
@Test public void highFrequencyCustomers_ShouldHaveMoreThan3Orders() {
Connection conn = getTestDbConnection();
ResultSet rs = conn.createStatement().executeQuery(
"SELECT COUNT(*) FROM customers WHERE /* same query */ ...");
int count = rs.getInt(1);
Assert.assertTrue(count >= 0, "Query should execute without error");
} // Defect fields QA should always fill: // ID → auto-generated // Title → specific and descriptive // Priority → P1 Critical, P2 High, P3 Medium, P4 Low // Severity → Blocker, Critical, Major, Minor, Trivial // Status → from defect lifecycle // Steps → exact reproduction steps (numbered) // Expected → what should happen // Actual → what actually happened // Environment → browser, OS, version, URL // Screenshot/Video → proof of the issue // Assignee → developer responsible
// Login Form Test Cases: TC01: Valid email + valid password → login success, redirect to dashboard TC02: Valid email + wrong password → error "Invalid credentials" TC03: Unregistered email → error "Email not found" TC04: Empty email → error "Email is required" TC05: Empty password → error "Password is required" TC06: Both fields empty → errors on both fields TC07: Valid email + password with leading/trailing spaces → should trim + login TC08: SQL injection in email: "admin'--" → should be sanitized, no crash TC09: XSS in password: "<script>alert(1)</script>" → should not execute TC10: Remember Me checkbox → session persists after browser close TC11: Forgot Password link → navigates to password reset page TC12: Valid credentials after 3 failed attempts → account locked for 15 minutes TC13: Login with keyboard (Tab to navigate, Enter to submit) → should work TC14: Password characters masked with ● → no plain text visible
// Pre-request script: generate dynamic data
pm.environment.set("timestamp", Date.now());
pm.environment.set("randomEmail", "test" + Math.random()+""+"@test.com");
// Tests tab: assertions
pm.test("Status code is 200", () => pm.response.to.have.status(200));
pm.test("Response time < 1000ms", () => pm.expect(pm.response.responseTime).to.be.below(1000));
pm.test("Content-Type is JSON", () => pm.response.to.have.header("Content-Type","application/json; charset=utf-8"));
pm.test("User has required fields", () => {
const body = pm.response.json();
pm.expect(body).to.have.property("userId");
pm.expect(body).to.have.property("email");
pm.expect(body.status).to.eql("ACTIVE");
});
// Chain: extract token for next request
const token = pm.response.json().accessToken;
pm.environment.set("authToken", token); // TestNG features not in JUnit 4:
@Test(groups="smoke", priority=1, retryAnalyzer=RetryAnalyzer.class)
public void loginTest() { ... }
@Test(groups="regression", dependsOnMethods="loginTest")
public void dashboardTest() { ... }
@DataProvider(name="users")
public Object[][] userData() {
return new Object[][]{{"admin","pass1"},{"user","pass2"}};
}
@Test(dataProvider="users")
public void loginWithMultipleUsers(String u, String p) { ... }
// testng.xml
// <suite parallel="methods" thread-count="5">
// <test name="Smoke">
// <groups><run><include name="smoke"/></run></groups> // Without POM (bad - locators in test)
@Test public void loginTest_Bad() {
driver.findElement(By.id("user")).sendKeys("admin");
driver.findElement(By.id("pass")).sendKeys("pass");
driver.findElement(By.cssSelector(".btn-login")).click();
// 500 tests all have this code → if id changes, 500 tests break!
}
// With POM (good - locators in page class)
public class LoginPage {
private final By emailField = By.id("user");
private final By passField = By.id("pass");
private final By loginBtn = By.cssSelector(".btn-login");
private WebDriver driver;
public LoginPage(WebDriver d) { this.driver=d; }
public DashboardPage login(String email, String pass) {
driver.findElement(emailField).sendKeys(email);
driver.findElement(passField).sendKeys(pass);
driver.findElement(loginBtn).click();
return new DashboardPage(driver);
}
}
// Test becomes:
@Test public void loginTest_Good() {
DashboardPage dash = new LoginPage(driver).login("admin","pass");
Assert.assertTrue(dash.isLoaded());
// If ID changes → update ONLY LoginPage, 500 tests still work
} // Jenkins Freestyle Job configuration:
// Build Step: Invoke Maven
// Goals: test -Dgroups=regression -Dbrowser=chrome -Dheadless=true
// Post-build: Publish TestNG Results
// Report XMLs: target/surefire-reports/*.xml
// Post-build: Allure Report
// Post-build: Email Notification on failure
// Jenkinsfile (Pipeline as Code - preferred):
pipeline {
agent any
triggers { cron("0 22 * * 1-5") } // nightly Mon-Fri
stages {
stage("Test") {
steps { sh "mvn test -Dgroups=regression -Dbrowser=chrome" }
}
stage("Report") {
steps { allure results: [[path: "target/allure-results"]] }
}
}
post {
failure { emailext to:"qa-team@tcs.com",
subject:"Regression FAILED: ${env.JOB_NAME}",
body:"Build: ${env.BUILD_URL}" }
}
} Infosys Interview Process
IT Services · MNC · Pan-India + Global · 2–3 Rounds
💻 InfyTQ / Online Assessment
Infosys InfyTQ platform has 4 sections: Logical Reasoning (15 min), Verbal Ability (20 min), Quantitative Aptitude (25 min), and Coding (2 problems, 30 min). Coding is Easy level. Focus on DSA basics.
public int secondSmallest(int[] arr) {
int first=Integer.MAX_VALUE, second=Integer.MAX_VALUE;
for (int n : arr) {
if (n < first) { second=first; first=n; }
else if (n<second && n!=first) second=n;
}
return second;
}
// [3,1,4,1,5,9,2,6] → 2 [1,1,1] → MAX_VALUE public boolean isPalindrome(String s) {
int lo=0, hi=s.length()-1;
while (lo<hi) {
while (lo<hi && !Character.isLetterOrDigit(s.charAt(lo))) lo++;
while (lo<hi && !Character.isLetterOrDigit(s.charAt(hi))) hi--;
if (Character.toLowerCase(s.charAt(lo)) !=
Character.toLowerCase(s.charAt(hi))) return false;
lo++; hi--;
}
return true;
}
// "A man, a plan, a canal: Panama" → true
// "race a car" → false public int gcd(int a, int b) {
return b==0 ? a : gcd(b, a%b);
}
// Iterative version:
public int gcdIter(int a, int b) {
while (b!=0) { int t=b; b=a%b; a=t; }
return a;
}
// GCD(12,8)=4 GCD(100,75)=25 GCD(17,5)=1
// LCM using GCD:
public long lcm(int a, int b) { return (long)a/gcd(a,b)*b; }
// LCM(4,6)=12 LCM(3,5)=15 public void printTriangle(int n) {
for (int i=1;i<=n;i++) {
for (int j=1;j<=i;j++) System.out.print("* ");
System.out.println();
}
}
// n=4:
// *
// * *
// * * *
// * * * *
// Floyd's triangle (numbers):
public void floyd(int n) {
int num=1;
for (int i=1;i<=n;i++) {
for (int j=1;j<=i;j++) System.out.print(num+++" ");
System.out.println();
}
}
// 1 / 2 3 / 4 5 6 / 7 8 9 10 public boolean isPrime(int n) {
if (n<2) return false;
if (n==2) return true;
if (n%2==0) return false;
for (int i=3; i*i<=n; i+=2) // check only odd divisors
if (n%i==0) return false;
return true;
}
// 2→true 3→true 4→false 17→true 100→false
// Test cases to mention:
// 0, 1 → false
// 2 → true (only even prime)
// Negative → false
// Large prime: 104729 → true public int missingNumber(int[] nums) {
int n = nums.length;
int expected = n*(n+1)/2;
int actual = 0;
for (int num : nums) actual += num;
return expected - actual;
}
// [3,0,1] → 2 [9,6,4,2,3,5,7,0,1] → 8
// XOR approach (avoids overflow for large N):
public int missingXOR(int[] nums) {
int xor = nums.length;
for (int i=0;i<nums.length;i++) xor ^= i ^ nums[i];
return xor;
} public Map<Character,Integer> charFrequency(String s) {
Map<Character,Integer> freq = new LinkedHashMap<>();
for (char c : s.toCharArray())
freq.merge(c, 1, Integer::sum);
return freq;
}
// "hello" → {h:1, e:1, l:2, o:1}
// Print in order of first occurrence:
void printFrequency(String s) {
Map<Character,Integer> freq = charFrequency(s);
freq.forEach((c,count) ->
System.out.printf("%c: %d%n", c, count));
}
// Find most frequent character:
char maxFreqChar(String s) {
Map<Character,Long> freq = s.chars()
.mapToObj(c->(char)c)
.collect(Collectors.groupingBy(c->c, Collectors.counting()));
return freq.entrySet().stream()
.max(Map.Entry.comparingByValue()).get().getKey();
} public List<Integer> sieve(int n) {
boolean[] isComposite = new boolean[n+1];
List<Integer> primes = new ArrayList<>();
for (int i=2;i<=n;i++) {
if (!isComposite[i]) {
primes.add(i);
for (long j=(long)i*i; j<=n; j+=i)
isComposite[(int)j]=true;
}
}
return primes;
}
// sieve(30) → [2,3,5,7,11,13,17,19,23,29]
// Time: O(n log log n) Space: O(n) public void transpose(int[][] matrix) {
int n = matrix.length;
for (int i=0;i<n;i++)
for (int j=i+1;j<n;j++) { // j starts from i+1 to avoid double-swap
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// [[1,2,3],[4,5,6],[7,8,9]]
// → [[1,4,7],[2,5,8],[3,6,9]] public class QueueUsingStacks {
private Deque<Integer> inbox = new ArrayDeque<>();
private Deque<Integer> outbox = new ArrayDeque<>();
public void enqueue(int val) { inbox.push(val); }
public int dequeue() {
if (outbox.isEmpty()) {
while (!inbox.isEmpty()) outbox.push(inbox.pop());
}
if (outbox.isEmpty()) throw new NoSuchElementException();
return outbox.pop();
}
public int peek() {
if (outbox.isEmpty())
while (!inbox.isEmpty()) outbox.push(inbox.pop());
return outbox.peek();
}
}
// Amortized O(1) dequeue: each element moves at most twice Meta Interview Process
FAANG · Facebook · Instagram · WhatsApp · 5–7 Rounds
💻 Coding Round
Meta coding rounds are identical to SWE rounds — LeetCode Medium/Hard. Fast-paced. Meta values both speed and clean code. Think out loud. They specifically look for optimal solutions and clear communication.
public int numIslands(char[][] grid) {
int count = 0;
for (int i = 0; i < grid.length; i++)
for (int j = 0; j < grid[0].length; j++)
if (grid[i][j] == '1') { dfs(grid, i, j); count++; }
return count;
}
void dfs(char[][] g, int i, int j) {
if (i < 0 || j < 0 || i >= g.length || j >= g[0].length || g[i][j] != '1') return;
g[i][j] = '0';
dfs(g,i+1,j); dfs(g,i-1,j); dfs(g,i,j+1); dfs(g,i,j-1);
}
// [[1,1,0],[1,0,0],[0,0,1]] → 2 public Node cloneGraph(Node node) {
if (node == null) return null;
Map<Node, Node> map = new HashMap<>();
return clone(node, map);
}
private Node clone(Node n, Map<Node, Node> map) {
if (map.containsKey(n)) return map.get(n);
Node copy = new Node(n.val);
map.put(n, copy);
for (Node nb : n.neighbors)
copy.neighbors.add(clone(nb, map));
return copy;
} public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
List<int[]> res = new ArrayList<>();
for (int[] iv : intervals) {
if (res.isEmpty() || res.get(res.size()-1)[1] < iv[0])
res.add(iv);
else
res.get(res.size()-1)[1] = Math.max(res.get(res.size()-1)[1], iv[1]);
}
return res.toArray(new int[0][]);
}
// [[1,3],[2,6],[8,10],[15,18]] → [[1,6],[8,10],[15,18]] public boolean exist(char[][] board, String word) {
for (int i = 0; i < board.length; i++)
for (int j = 0; j < board[0].length; j++)
if (dfs(board, word, 0, i, j)) return true;
return false;
}
boolean dfs(char[][] b, String w, int k, int i, int j) {
if (k == w.length()) return true;
if (i<0||j<0||i>=b.length||j>=b[0].length||b[i][j]!=w.charAt(k)) return false;
char tmp = b[i][j]; b[i][j] = '#';
boolean found = dfs(b,w,k+1,i+1,j)||dfs(b,w,k+1,i-1,j)||
dfs(b,w,k+1,i,j+1)||dfs(b,w,k+1,i,j-1);
b[i][j] = tmp;
return found;
} public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] res = new int[n];
res[0] = 1;
for (int i = 1; i < n; i++)
res[i] = res[i-1] * nums[i-1]; // left products
int right = 1;
for (int i = n-1; i >= 0; i--) {
res[i] *= right; // multiply right product
right *= nums[i];
}
return res;
}
// [1,2,3,4] → [24,12,8,6] public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int n : nums) set.add(n);
int max = 0;
for (int n : set) {
if (!set.contains(n - 1)) { // start of sequence
int len = 1;
while (set.contains(n + len)) len++;
max = Math.max(max, len);
}
}
return max;
}
// [100,4,200,1,3,2] → 4 (sequence 1,2,3,4) public String minWindow(String s, String t) {
Map<Character,Integer> need = new HashMap<>(), window = new HashMap<>();
for (char c : t.toCharArray()) need.merge(c, 1, Integer::sum);
int have = 0, required = need.size(), l = 0, minLen = Integer.MAX_VALUE, start = 0;
for (int r = 0; r < s.length(); r++) {
char c = s.charAt(r);
window.merge(c, 1, Integer::sum);
if (need.containsKey(c) && window.get(c).equals(need.get(c))) have++;
while (have == required) {
if (r - l + 1 < minLen) { minLen = r - l + 1; start = l; }
char lc = s.charAt(l++);
window.merge(lc, -1, Integer::sum);
if (need.containsKey(lc) && window.get(lc) < need.get(lc)) have--;
}
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
} public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int start = 0, maxLen = 0;
for (int i = 0; i < s.length(); i++) {
int odd = expand(s, i, i); // odd length
int even = expand(s, i, i + 1); // even length
int len = Math.max(odd, even);
if (len > maxLen) {
maxLen = len;
start = i - (len - 1) / 2;
}
}
return s.substring(start, start + maxLen);
}
int expand(String s, int l, int r) {
while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { l--; r++; }
return r - l - 1;
}
// "babad" → "bab", "cbbd" → "bb" class HitCounter {
private final Deque<Integer> times = new ArrayDeque<>();
public void hit(int timestamp) {
times.offer(timestamp);
}
public int getHits(int timestamp) {
while (!times.isEmpty() && times.peek() <= timestamp - 300)
times.poll();
return times.size();
}
}
// hit(1),hit(2),hit(3),getHits(4)→3, getHits(301)→2 public int search(int[] nums, int target) {
int lo = 0, hi = nums.length - 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (nums[mid] == target) return mid;
if (nums[lo] <= nums[mid]) { // left half sorted
if (nums[lo] <= target && target < nums[mid]) hi = mid - 1;
else lo = mid + 1;
} else { // right half sorted
if (nums[mid] < target && target <= nums[hi]) lo = mid + 1;
else hi = mid - 1;
}
}
return -1;
}
// [4,5,6,7,0,1,2] target=0 → 4, target=3 → -1 🌟 Behavioral / Googliness
Meta behavioral evaluates impact, speed, and collaboration. Always quantify impact. Meta moves fast — show you ship things. Use the STAR format but keep answers concise.
// STAR Framework: // Situation: "Our regression suite took 6 hours and ran manually every Friday" // Task: "I was asked to reduce testing cycle time" // Action: "Built Selenium Grid with 20 parallel threads + TestNG parallel suite" // Result: "Suite now runs in 22 minutes. Releases went from weekly to daily. // Defect escape rate dropped from 12% to 2.8%"
// Good answer structure: // 1. What was uncertain? (requirements unclear, tech unproven) // 2. How did you reduce uncertainty cheaply? (spike, prototype, user test) // 3. What did you ship in the first week vs month? // 4. What did you learn from early users/data? // 5. How did you iterate?
// Do NOT say: // "They were difficult and I had to work around them" // DO say: // "We had different approaches — I suggested we each build a POC, // present to the team, and let data decide. They agreed. // Their approach turned out better for part A, mine for part B. // We shipped a hybrid solution that neither of us would have built alone."
// Strong answer pattern: // "I chose Tool X because [valid reason at the time]. // After 3 weeks, we saw [specific problem metric]. // I ran a 2-day spike on Tool Y as an alternative. // Within 5 days of the spike, we migrated. // I also added a decision log so future choices have documented trade-offs."
// Example: // "I noticed the onboarding docs were causing every new SDET to spend // 3 days on environment setup. Not my job officially. // I spent one weekend documenting it properly with screenshots. // New hire ramp-up time dropped from 3 days to 4 hours. // The docs are now the official onboarding guide."
// Meta-scale testing philosophy: // - Canary deploys: 0.1% → 1% → 10% → 100% // - Feature flags: test in production with limited exposure // - Dark launch: backend changes get real traffic, users see old UI // - Chaos: kill services deliberately to test resilience // - SLO-based: automate rollback when error rate exceeds threshold
// Good structure: // 1. What was the disagreement? (technical, process, priority) // 2. What data did you bring to the conversation? // 3. How did you raise it? (1-on-1, written proposal, team meeting?) // 4. What was the outcome? (your view won / their view won / compromise) // 5. How did you commit after the decision?
// Meta prioritization signals: // - User impact: affects how many users? how severely? // - Revenue impact: is this on the critical path to a launch? // - Dependency: is someone blocked on this? // - Reversibility: easy to do later, or now-or-never? // - Time-sensitivity: deadline-driven vs evergreen?
// Strong answer elements: // 1. Specific product/team you're joining // 2. Why their scale is uniquely interesting to you as a QA engineer // 3. Something specific you've read about their engineering culture // (e.g., Meta Engineering blog, their testing framework papers) // 4. What you'd bring that they don't currently have
PhonePe Interview Process
Indian FinTech · UPI Payments · Bangalore · 4–5 Rounds
💳 Technical Round 1
PhonePe Tech 1: Payment domain knowledge + automation skills. Domain knowledge directly determines shortlisting. Know UPI, payment flows, and fintech testing.
// Test categories: // 1. HAPPY PATH: valid VPA, valid amount, correct PIN → success // 2. VALIDATION: invalid VPA, zero amount, over-limit, wrong PIN // 3. BANK FAILURES: receiver bank down → PENDING → auto-refund // 4. NETWORK: drop after debit, before credit → idempotency check // 5. SECURITY: PIN in logs? Device binding? Rate limiting? // 6. CONCURRENCY: same amount sent twice within 1 second — 1 debit only
@Test
public void testPaymentIdempotency() {
String idempotencyKey = UUID.randomUUID().toString();
String requestBody = "{\"amount\":500,\"vpa\":\"test@upi\"}";
// First call - creates payment
String paymentId1 = given()
.header("Idempotency-Key", idempotencyKey)
.header("Authorization", "Bearer " + getToken())
.body(requestBody).contentType(ContentType.JSON)
.when().post("/v1/payments")
.then().statusCode(201)
.extract().path("paymentId");
// Second call - same key, must return SAME paymentId
String paymentId2 = given()
.header("Idempotency-Key", idempotencyKey)
.header("Authorization", "Bearer " + getToken())
.body(requestBody).contentType(ContentType.JSON)
.when().post("/v1/payments")
.then()
.statusCode(200) // NOT 201 - already processed
.body("idempotent", equalTo(true))
.extract().path("paymentId");
Assert.assertEquals(paymentId1, paymentId2,
"Same Idempotency-Key must return same paymentId - no double charge");
} // OTP Test Matrix: // TC1: Correct OTP within 5 min → 200 logged in // TC2: Wrong OTP → 401 with "Invalid OTP" // TC3: Correct OTP after 5 min 1 sec → 401 "OTP expired" // TC4: Same OTP used twice → 401 on second use // TC5: Wrong OTP 3 times → account locked 30 min // TC6: Resend OTP → old OTP now invalid // TC7: OTP in /send-otp response body? → SECURITY FAIL // TC8: OTP visible in network logs? → SECURITY FAIL
public void validateWebhookSignature(String rawBody, String receivedSig, String secret)
throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec key = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(key);
byte[] hash = mac.doFinal(rawBody.getBytes(StandardCharsets.UTF_8));
String computed = Base64.getEncoder().encodeToString(hash);
Assert.assertEquals(computed, receivedSig, "Webhook signature mismatch!");
}
// Test cases:
// 1. Valid body + valid secret → signatures match → accept
// 2. Tampered body (amount changed) + valid secret → mismatch → 400
// 3. Valid body + wrong secret → mismatch → 400
// 4. Missing X-PhonePe-Signature header → reject immediately // JMeter thread group config:
// Threads: 1000
// Ramp-up: 1 second (all at once)
// Loop: 1
// Each request:
// Header: Idempotency-Key = ${__UUID()} <- unique per thread
// Body: {"amount":100, "vpa":"merchant@upi"}
// Assertions:
// Response Code: 200 or 201
// Response Time: < 3000ms
// Post-test DB validation:
// SELECT COUNT(*) FROM payments WHERE batch_id = ? → should = 1000
// SELECT SUM(amount) FROM wallet_debits WHERE batch_id = ? → should = 100000 @Test
public void testTransactionHistoryPagination() {
// Get page 1
Response page1 = given()
.header("Authorization", "Bearer " + getToken())
.queryParam("page", 1)
.queryParam("size", 20)
.when().get("/v1/transactions")
.then()
.statusCode(200)
.body("data.size()", equalTo(20))
.body("total", greaterThan(0))
.body("hasMore", equalTo(true))
.extract().response();
// Collect all IDs from page 1
List<String> page1Ids = page1.path("data.transactionId");
// Get page 2 - must be different records
List<String> page2Ids = given()
.header("Authorization", "Bearer " + getToken())
.queryParam("page", 2).queryParam("size", 20)
.when().get("/v1/transactions")
.then().statusCode(200).extract().path("data.transactionId");
// No overlap between pages
page1Ids.retainAll(page2Ids);
Assert.assertTrue(page1Ids.isEmpty(), "Pages must not contain duplicate transactions");
} // IDOR Test:
String userBToken = loginAsUserB();
String userATransactionId = createTransactionAsUserA();
given()
.header("Authorization", "Bearer " + userBToken) // User B's token
.pathParam("id", userATransactionId) // User A's transaction
.when().get("/v1/transactions/{id}")
.then().statusCode(403); // MUST be 403, not 200
// JWT Manipulation Test:
String validToken = loginAsUserA();
String manipulatedToken = manipulateJwtUserId(validToken, "admin");
given().header("Authorization", "Bearer " + manipulatedToken)
.when().get("/v1/account/balance")
.then().statusCode(401); // Signature validation must catch this public class BaseApiTest {
protected static RequestSpecification authSpec;
@BeforeClass
public static void setup() {
// Get auth token once per class
String token = AuthHelper.getToken();
authSpec = new RequestSpecBuilder()
.setBaseUri(Config.getBaseUrl())
.addHeader("Authorization", "Bearer " + token)
.addHeader("Content-Type", "application/json")
.addFilter(new AllureRestAssured()) // attach to Allure report
.build();
}
}
// Service class
public class PaymentService {
public String createPayment(String vpa, int amount) {
return given(authSpec)
.header("Idempotency-Key", UUID.randomUUID().toString())
.body(String.format("{\"vpa\":\"%s\",\"amount\":%d}", vpa, amount))
.when().post("/v1/payments")
.then().statusCode(201)
.extract().path("paymentId");
}
} Razorpay Interview Process
Indian FinTech · API-First Payments · Bangalore · 3–4 Rounds
🔌 API + Domain Round
Razorpay is API-first. This round is the most important — show deep REST API testing, payment webhook validation, and SDK testing knowledge. Every question ties back to payments.
@Test
public void testWebhookSignatureValid() throws Exception {
String orderId = "order_test123";
String paymentId = "pay_test456";
String secret = "whsec_test";
// Compute expected signature (what Razorpay sends)
String body = orderId + "|" + paymentId;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(), "HmacSHA256"));
String expectedSig = Hex.encodeHexString(mac.doFinal(body.getBytes()));
// Verify your handler accepts it
Assert.assertTrue(WebhookValidator.verify(orderId, paymentId, expectedSig, secret));
}
@Test
public void testWebhookSignatureTampered() throws Exception {
// Change the amount in the payload AFTER signing
Assert.assertFalse(
WebhookValidator.verify("order_TAMPERED", "pay_test456", validSignature, secret)
);
} describe('Razorpay Checkout SDK', () => {
beforeEach(() => {
// Mock Razorpay payment success
cy.intercept('POST', 'https://api.razorpay.com/v1/payments/create/ajax', {
statusCode: 200,
body: {
razorpay_payment_id: 'pay_test123',
razorpay_order_id: 'order_test456',
razorpay_signature: 'sig_abc'
}
}).as('razorpayPayment');
});
it('completes payment and shows success screen', () => {
cy.visit('/checkout');
cy.get('[data-testid="pay-button"]').click();
// Razorpay modal opens (injected iframe)
cy.frameLoaded('.razorpay-checkout-frame');
cy.iframe().find('[data-testid="submit-button"]').click();
cy.wait('@razorpayPayment');
cy.get('[data-testid="success-message"]').should('be.visible');
cy.get('[data-testid="order-id"]').should('contain', 'order_test456');
});
}); public class RazorpayOrderTest {
private static final String BASE_URL = "https://api.razorpay.com";
private String encodeCredentials() {
return Base64.getEncoder().encodeToString(
(KEY_ID + ":" + KEY_SECRET).getBytes()
);
}
@Test
public void createOrder_ValidInput_Returns200WithOrderId() {
String orderId = given()
.baseUri(BASE_URL)
.header("Authorization", "Basic " + encodeCredentials())
.body("{\"amount\":50000,\"currency\":\"INR\",\"receipt\":\"order_rcpt_001\"}")
.contentType(ContentType.JSON)
.when().post("/v1/orders")
.then()
.statusCode(200)
.body("status", equalTo("created"))
.body("amount", equalTo(50000)) // 50000 paise = ₹500
.body("currency", equalTo("INR"))
.body("receipt", equalTo("order_rcpt_001"))
.body("id", startsWith("order_"))
.extract().path("id");
// Fetch the created order
given()
.baseUri(BASE_URL)
.header("Authorization", "Basic " + encodeCredentials())
.when().get("/v1/orders/" + orderId)
.then()
.statusCode(200)
.body("id", equalTo(orderId))
.body("status", equalTo("created"));
}
} // Razorpay test cards for specific failures:
// Success: 4111 1111 1111 1111 CVV: 123 Expiry: any future date
// Insufficient Funds: Use test card with specific last 4 digits per Razorpay docs
// Expired Card: Any past expiry date
// Invalid CVV: CVV: 000
// REST Assured test for declined payment:
given().body("{\"card\":{\"number\":\"4000000000000002\"," + // Decline card
"\"cvv\":\"123\",\"expiry_month\":12,\"expiry_year\":30}," +
"\"amount\":10000,\"currency\":\"INR\"}")
.when().post("/v1/payments")
.then()
.statusCode(400)
.body("error.code", equalTo("BAD_REQUEST_ERROR"))
.body("error.description", containsString("Your payment has been declined"))
.body("error.reason", equalTo("payment_failed")); name: Razorpay API Tests
on:
push:
branches: [main]
schedule:
- cron: '0 2 * * *' # Nightly 2 AM
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with: { java-version: '17', distribution: 'temurin' }
- name: Run API Tests
env:
RAZORPAY_KEY_ID: ${{ secrets.RAZORPAY_KEY_ID }}
RAZORPAY_KEY_SECRET: ${{ secrets.RAZORPAY_KEY_SECRET }}
ENV: test
run: mvn test -Dgroups=api-smoke -Denv=${{ env.ENV }}
- name: Upload Allure Report
if: always()
uses: actions/upload-artifact@v3
with: { name: allure-results, path: target/allure-results } // Integration test points: // 1. POST /v1/orders → assert order_id returned, status="created" // 2. Checkout opens → assert order_id embedded correctly in SDK init // 3. Payment attempt → mock NPCI success, assert payment_id returned // 4. Webhook received → assert signature valid, payload matches order // 5. Order fulfilled → assert order status updated to "paid" // 6. E2E amount check → ₹500 charged = ₹500 credited (minus Razorpay fee)
// Load secrets safely
public class Config {
public static String getRazorpayKey() {
String key = System.getenv("RAZORPAY_KEY_ID");
if (key == null || key.isBlank())
throw new IllegalStateException(
"RAZORPAY_KEY_ID not set. Add to .env or CI secrets.");
return key;
}
}
// Mask sensitive fields in REST Assured logs
RestAssured.filters(new RequestLoggingFilter(
LogDetail.ALL, true,
new PrintStream(new FilterOutputStream(System.out) {
// Mask Authorization header
})
)); Swiggy Interview Process
Indian Product · Food Tech · Bangalore · 4 Rounds
🔬 Technical Round
Swiggy Technical: Selenium, API Testing, Java, real-time testing. Swiggy values domain knowledge of food-tech delivery systems. Real-time order tracking and GPS-based testing are unique to Swiggy.
// State transition test
@Test
public void orderTracking_CompleteFlow_AllStateTransitionsVerified() {
String orderId = placeTestOrder();
// State 1: ORDER_PLACED
assertOrderStatus(orderId, "ORDER_PLACED");
assertPushNotificationSent(orderId, "ORDER_PLACED");
// Simulate restaurant accepting
simulateRestaurantAccept(orderId);
waitForStatusChange(orderId, "RESTAURANT_ACCEPTED", 30);
assertETAUpdated(orderId);
// Simulate dispatch
simulatePickup(orderId);
waitForStatusChange(orderId, "OUT_FOR_DELIVERY", 60);
// Verify GPS tracking active
GPSCoordinates coords = getDeliveryPartnerLocation(orderId);
Assert.assertNotNull(coords, "GPS coordinates must be available during delivery");
// Simulate delivery
simulateDelivery(orderId);
waitForStatusChange(orderId, "DELIVERED", 30);
assertOrderCompletionNotification(orderId);
} @Test
public void addItemToCart_ValidItem_CartUpdatedCorrectly() {
String itemId = "ITEM_PIZZA_MARGHERITA";
int qty = 2;
given()
.header("Authorization", "Bearer " + userToken)
.body(String.format("{\"itemId\":\"%s\",\"quantity\":%d,\"restaurantId\":\"REST_001\"}", itemId, qty))
.contentType(ContentType.JSON)
.when().post("/v2/cart/items")
.then()
.statusCode(200)
.body("cart.itemCount", equalTo(1))
.body("cart.items[0].itemId", equalTo(itemId))
.body("cart.items[0].quantity", equalTo(qty))
.body("cart.totalPrice", greaterThan(0f))
.body("cart.restaurantId", equalTo("REST_001"));
}
@Test
public void addItemFromDifferentRestaurant_ShouldReject() {
// Cart already has item from REST_001
addItemToCart("ITEM_001", "REST_001");
// Trying to add from REST_002
given()
.header("Authorization", "Bearer " + userToken)
.body("{\"itemId\":\"ITEM_002\",\"quantity\":1,\"restaurantId\":\"REST_002\"}")
.contentType(ContentType.JSON)
.when().post("/v2/cart/items")
.then()
.statusCode(409) // Conflict - multi-restaurant cart not allowed
.body("error.code", equalTo("MULTI_RESTAURANT_CART_NOT_ALLOWED"));
} // AppiumDriver setup for Android
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName", "Android");
caps.setCapability("deviceName", "emulator-5554");
caps.setCapability("appPackage", "in.swiggy.android");
caps.setCapability("appActivity", ".SplashActivity");
caps.setCapability("automationName", "UIAutomator2");
caps.setCapability("newCommandTimeout", 120);
caps.setCapability("noReset", false); // fresh install per test run
driver = new AndroidDriver(new URL("http://localhost:4723"), caps);
// Network condition simulation
((AndroidDriver)driver).setNetworkConnection(
new NetworkConnectionSetting(false, true, false) // WiFi only (no mobile data)
); // axe-core accessibility test via Selenium WebDriver (web)
JavascriptExecutor js = (JavascriptExecutor) driver;
Object result = js.executeAsyncScript(
"var cb = arguments[arguments.length-1];" +
"axe.run({ runOnly: ['wcag2a','wcag2aa'] }, cb);"
);
@SuppressWarnings("unchecked")
Map<String, Object> axeResult = (Map<String, Object>) result;
List<?> violations = (List<?>) axeResult.get("violations");
Assert.assertEquals(violations.size(), 0,
"Accessibility violations found: " + violations.toString()); Zomato Interview Process
Indian Product · Food Tech · Gurugram HQ · 3–4 Rounds
🔬 Technical Round
Zomato Tech: Java, Selenium, API testing, and food-tech domain knowledge. Fast-paced interviews — be concise and structured. Zomato values engineers who understand their core challenges: food discovery, dynamic pricing, and live order tracking.
// Feature file: restaurant_search.feature
Feature: Restaurant Search
Background:
Given I am logged into Zomato app
And my delivery location is "Koramangala, Bangalore"
Scenario: Search returns relevant cuisine results
When I search for "Pizza" in the search bar
Then I should see at least 5 restaurants serving pizza
And all results should be within 10km delivery radius
And results should be sorted by delivery time by default
Scenario: Filter by rating
Given I search for "Burger"
When I apply rating filter "4 stars and above"
Then all displayed restaurants should have rating >= 4.0
// Step Definition (Java):
@When("I search for {string} in the search bar")
public void searchForRestaurant(String cuisine) {
searchPage.enterSearchQuery(cuisine);
searchPage.tapSearch();
}
@Then("I should see at least {int} restaurants serving pizza")
public void verifyMinimumResults(int minCount) {
Assert.assertTrue(searchPage.getResultCount() >= minCount,
"Expected at least " + minCount + " results");
} @Test
public void liveTracking_ActiveOrder_MapAndStatusVisible() {
// Place a test order (via API to skip UI setup)
String orderId = orderApi.placeTestOrder();
// Navigate to tracking page
driver.get(BASE_URL + "/order-tracking/" + orderId);
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));
// Map container visible
WebElement mapContainer = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("tracking-map"))
);
Assert.assertTrue(mapContainer.isDisplayed());
// Delivery partner marker on map
WebElement partnerMarker = wait.until(
ExpectedConditions.presenceOfElementLocated(By.cssSelector(".delivery-partner-marker"))
);
Assert.assertTrue(partnerMarker.isDisplayed(), "Partner location marker should be on map");
// ETA should show time remaining
WebElement eta = driver.findElement(By.cssSelector("[data-testid='eta-countdown']"));
String etaText = eta.getText();
Assert.assertTrue(etaText.matches("\d+ min(s?)"), "ETA should show minutes: " + etaText);
// Call partner button
Assert.assertTrue(
driver.findElement(By.cssSelector("[data-testid='call-partner-btn']")).isEnabled()
);
} @Test
public void placeOrder_ValidInput_Returns201WithOrderDetails() {
String requestBody = """
{
"restaurantId": "REST_TEST_001",
"items": [
{"itemId": "ITEM_001", "quantity": 2, "customization": "no onion"},
{"itemId": "ITEM_002", "quantity": 1}
],
"deliveryAddressId": "ADDR_TEST_001",
"paymentMethod": "UPI",
"couponCode": "FIRST10"
}""";
given()
.header("Authorization", "Bearer " + getUserToken())
.body(requestBody).contentType(ContentType.JSON)
.when().post("/api/v2/orders")
.then()
.statusCode(201)
.body("orderId", startsWith("ZOM"))
.body("status", equalTo("ACCEPTED"))
.body("estimatedDeliveryMinutes", both(greaterThan(15)).and(lessThan(90)))
.body("totalAmount", greaterThan(0f))
.body("discountApplied", greaterThan(0f)) // coupon applied
.time(lessThan(2000L)); // order placement SLA
} public class RestaurantPage extends BasePage {
@FindBy(css = "[data-testid='restaurant-name']")
private WebElement restaurantName;
@FindBy(css = "[data-testid='add-to-cart-btn']")
private List<WebElement> addToCartButtons;
@FindBy(css = "[data-testid='menu-category']")
private List<WebElement> menuCategories;
public RestaurantPage(WebDriver driver) { super(driver); }
public String getRestaurantName() {
return waitForVisible(restaurantName).getText();
}
public CartPage addFirstItemToCart() {
waitForElements(addToCartButtons).get(0).click();
return new CartPage(driver);
}
public int getMenuCategoryCount() {
return waitForElements(menuCategories).size();
}
} Atlassian Interview Process
Global Product · Jira · Confluence · Remote-First · 4 Rounds
💻 Coding Round
Atlassian prioritizes code quality over speed. They do code reviews during the interview. Write clean, readable, well-named code. Comment non-obvious logic. They test algorithmic thinking and OOP design.
public int minSprints(int n, int[][] deps) {
int[] indegree = new int[n + 1];
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i <= n; i++) adj.add(new ArrayList<>());
for (int[] dep : deps) {
adj.get(dep[1]).add(dep[0]); // dep[1] must complete before dep[0]
indegree[dep[0]]++;
}
Queue<Integer> queue = new LinkedList<>();
for (int i = 1; i <= n; i++)
if (indegree[i] == 0) queue.offer(i);
int sprints = 0, processed = 0;
while (!queue.isEmpty()) {
int size = queue.size();
sprints++;
for (int i = 0; i < size; i++) {
int ticket = queue.poll();
processed++;
for (int next : adj.get(ticket))
if (--indegree[next] == 0) queue.offer(next);
}
}
return processed == n ? sprints : -1; // -1 if cycle detected
}
// 6 tickets, deps=[[2,1],[3,1],[4,2],[5,3]] → 3 sprints class MyHashMap<K, V> {
private static final int DEFAULT_CAPACITY = 16;
private static final float LOAD_FACTOR = 0.75f;
private LinkedList<Entry<K,V>>[] buckets;
private int size;
@SuppressWarnings("unchecked")
public MyHashMap() { buckets = new LinkedList[DEFAULT_CAPACITY]; }
public void put(K key, V value) {
int idx = getIndex(key);
if (buckets[idx] == null) buckets[idx] = new LinkedList<>();
for (Entry<K,V> e : buckets[idx]) {
if (e.key.equals(key)) { e.value = value; return; }
}
buckets[idx].add(new Entry<>(key, value));
size++;
if ((float) size / buckets.length > LOAD_FACTOR) resize();
}
public V get(K key) {
int idx = getIndex(key);
if (buckets[idx] == null) return null;
for (Entry<K,V> e : buckets[idx])
if (e.key.equals(key)) return e.value;
return null;
}
private int getIndex(K key) {
return Math.abs(key.hashCode()) % buckets.length;
}
private void resize() {
LinkedList<Entry<K,V>>[] old = buckets;
buckets = new LinkedList[old.length * 2];
size = 0;
for (LinkedList<Entry<K,V>> bucket : old)
if (bucket != null) for (Entry<K,V> e : bucket) put(e.key, e.value);
}
static class Entry<K,V> { K key; V value; Entry(K k, V v){key=k;value=v;} }
} public List<Issue> filterByAllLabels(List<Issue> issues, Set<String> required) {
if (required == null || required.isEmpty()) return issues;
return issues.stream()
.filter(issue -> issue.getLabels() != null &&
issue.getLabels().containsAll(required))
.sorted(Comparator.comparing(Issue::getPriority))
.collect(Collectors.toList());
}
// Test cases:
// Issue with labels {bug, backend, critical} - required {bug, backend} → INCLUDED
// Issue with labels {bug, frontend} - required {bug, backend} → EXCLUDED
// Issue with labels {} - required {bug} → EXCLUDED
// required = {} - all issues → ALL INCLUDED public class TestExecutionCounter {
private final AtomicInteger running = new AtomicInteger(0);
private final AtomicInteger completed = new AtomicInteger(0);
private final AtomicInteger failed = new AtomicInteger(0);
public void onTestStart() { running.incrementAndGet(); }
public void onTestPass() { running.decrementAndGet(); completed.incrementAndGet(); }
public void onTestFail() { running.decrementAndGet(); failed.incrementAndGet(); }
public void printSummary() {
System.out.printf("Running: %d | Passed: %d | Failed: %d | Total: %d%n",
running.get(), completed.get(), failed.get(),
completed.get() + failed.get());
}
public double getPassRate() {
int total = completed.get() + failed.get();
return total == 0 ? 0.0 : (double) completed.get() / total * 100;
}
}
// Thread-safe: AtomicInteger guarantees visibility and atomicity public class SlidingWindowRateLimiter {
private final ConcurrentHashMap<String, Deque<Long>> userRequests = new ConcurrentHashMap<>();
private final int maxRequests;
private final long windowMs;
public SlidingWindowRateLimiter(int maxRequests, long windowMs) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
}
public synchronized boolean allow(String userId) {
long now = System.currentTimeMillis();
userRequests.putIfAbsent(userId, new ArrayDeque<>());
Deque<Long> timestamps = userRequests.get(userId);
// Remove timestamps outside the window
while (!timestamps.isEmpty() && now - timestamps.peekFirst() >= windowMs)
timestamps.pollFirst();
if (timestamps.size() >= maxRequests) return false;
timestamps.addLast(now);
return true;
}
}
// SlidingWindowRateLimiter limiter = new SlidingWindowRateLimiter(100, 60_000);
// limiter.allow("user123") → true (if < 100 requests in last 60s) public Map<String, Object> flatten(Map<String, Object> nested, String prefix) {
Map<String, Object> flat = new LinkedHashMap<>();
nested.forEach((key, value) -> {
String fullKey = prefix.isEmpty() ? key : prefix + "." + key;
if (value instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> nestedMap = (Map<String, Object>) value;
flat.putAll(flatten(nestedMap, fullKey));
} else {
flat.put(fullKey, value);
}
});
return flat;
}
// Input: {"a": {"b": {"c": 1}, "d": 2}, "e": 3}
// Output: {"a.b.c": 1, "a.d": 2, "e": 3}
// Test cases:
// Empty map → empty map
// Single level → keys unchanged
// Deep nesting → all leaf keys with full path
// List values → stored as-is (not recursed) public interface JiraObserver {
void onIssueUpdate(String issueId, String newStatus, String assignee);
}
public class IssueTracker {
private final List<JiraObserver> observers = new ArrayList<>();
private final Map<String, String> issueStatus = new HashMap<>();
public void subscribe(JiraObserver observer) { observers.add(observer); }
public void unsubscribe(JiraObserver observer) { observers.remove(observer); }
public void updateIssueStatus(String issueId, String newStatus, String assignee) {
issueStatus.put(issueId, newStatus);
// Notify all observers
observers.forEach(o -> o.onIssueUpdate(issueId, newStatus, assignee));
}
}
// Usage:
IssueTracker tracker = new IssueTracker();
tracker.subscribe((id, status, assignee) ->
System.out.println("Email sent: " + id + " → " + status));
tracker.subscribe((id, status, assignee) ->
slackBot.notify("#eng-channel", id + " assigned to " + assignee));
tracker.updateIssueStatus("PROJ-123", "In Progress", "john.doe"); public class JQLParser {
record Condition(String field, String operator, String value) {}
public List<Condition> parse(String jql) {
List<Condition> conditions = new ArrayList<>();
// Split on AND/OR (simplified - treats all as AND)
String[] parts = jql.split("\s+(?i)AND\s+");
for (String part : parts) {
// Split on operator: =, !=, ~, in, not in
String[] tokens = part.trim().split("\s+", 3);
if (tokens.length == 3) {
conditions.add(new Condition(
tokens[0].trim(),
tokens[1].trim(),
tokens[2].trim().replaceAll("^\"|\"$", "") // remove quotes
));
}
}
return conditions;
}
}
// "project = MYPROJ AND status = Open AND assignee = john"
// → [{project,=,MYPROJ}, {status,=,Open}, {assignee,=,john}] public double predictVelocity(double[] history, int windowSize) {
if (history.length == 0) return 0.0;
int start = Math.max(0, history.length - windowSize);
double weightedSum = 0.0, totalWeight = 0.0;
for (int i = start; i < history.length; i++) {
double weight = i - start + 1; // 1, 2, 3, ... (most recent = highest)
weightedSum += history[i] * weight;
totalWeight += weight;
}
return Math.round(weightedSum / totalWeight * 10.0) / 10.0;
}
// history = [20, 22, 18, 25, 23], windowSize = 3
// Uses [18, 25, 23] with weights [1, 2, 3]
// = (18×1 + 25×2 + 23×3) / (1+2+3) = (18+50+69)/6 = 137/6 ≈ 22.8 // ROI Calculation Example: // Manual test time: 20 minutes per run // Runs per year: 52 (weekly regression) // Manual total: 20 × 52 = 1040 min/year // Automation creation: 3 hours = 180 min // Automation run time: 2 min per run // Automation total: 3h create + (2 × 52) = 180 + 104 = 284 min/year // Year 1 savings: 1040 - 284 = 756 min (12.6 hours) // Year 2+ savings: 1040 - 104 = 936 min/year (15.6 hours) // → Automate: ROI positive from year 1
🌟 Values Round
Atlassian evaluates 5 core values: Open company no bullshit · Don't #@!% the customer · Play as a team · Be the change you seek · Build with heart and balance.
// Strong answer pattern: // "I noticed our onboarding docs caused every new SDET to spend // 3 days on environment setup. Not in my JIRA backlog. // Spent one weekend documenting it with screenshots and video walkthroughs. // New hire ramp-up time dropped from 3 days to 4 hours. // The docs became the official onboarding guide — now maintained by the team." // Key elements: // 1. Problem: specific, with a cost (3 days × N people) // 2. Action: you took it personally (one weekend) // 3. Result: measurable (3 days → 4 hours) // 4. Leverage: others now benefit (team maintains it)
// Post-mortem structure (blameless): // 1. Timeline of what happened // 2. Impact: who was affected, for how long // 3. Root cause (the system/process, not a person) // 4. Contributing factors // 5. What we fixed immediately // 6. What we changed permanently (process/test/alert) // 7. Key learnings for the team
// SBI Feedback Model: // Situation: "In yesterday's code review for PR-442..." // Behaviour: "you approved the PR without running the tests locally..." // Impact: "...which caused the main branch to fail, blocking 4 other engineers for 2 hours." // Then: "I'd like us to agree on a definition of done for code reviews. Can we talk about it?" // NOT: "You always do this" or "Your code quality is bad"
// Strong answer elements: // 1. Specific product/team you're joining (not just "Atlassian") // 2. Scale argument: quality in Jira → impact on millions of dev teams // 3. Reference something from Atlassian Engineering blog // 4. A specific product pain point you want to help solve // 5. How your background uniquely fits their challenges
Wipro Interview Process
IT Services · MNC · Bangalore HQ · 2–3 Rounds
🔬 Technical Interview
Wipro Technical: QA fundamentals, STLC, testing types, basic Selenium, SQL. More theory-oriented than product companies. Communication skills are assessed equally with technical knowledge.
public int secondLargest(int[] arr) {
int first = Integer.MIN_VALUE;
int second = Integer.MIN_VALUE;
for (int n : arr) {
if (n > first) {
second = first;
first = n;
} else if (n > second && n != first) {
second = n;
}
}
if (second == Integer.MIN_VALUE)
throw new IllegalArgumentException("No second largest element");
return second;
}
// [1,2,3,4,5] → 4
// [5,5,5,5] → throws exception (no distinct second largest)
// [1] → throws exception -- Method 1: Correlated subquery
SELECT e.name, e.department, e.salary
FROM employees e
WHERE e.salary > (
SELECT AVG(salary)
FROM employees
WHERE department = e.department
);
-- Method 2: Window function (more efficient)
SELECT name, department, salary FROM (
SELECT name, department, salary,
AVG(salary) OVER (PARTITION BY department) AS dept_avg
FROM employees
) t
WHERE salary > dept_avg; // Native HTML dropdown - use Select class
WebElement dropdownElement = driver.findElement(By.id("country-select"));
Select dropdown = new Select(dropdownElement);
// Three ways to select:
dropdown.selectByVisibleText("India"); // by text
dropdown.selectByValue("IN"); // by value attribute
dropdown.selectByIndex(2); // by position
// Verify selection
String selected = dropdown.getFirstSelectedOption().getText();
Assert.assertEquals(selected, "India", "Wrong country selected");
// Get all options
List<WebElement> allOptions = dropdown.getOptions();
System.out.println("Total options: " + allOptions.size());
allOptions.forEach(opt -> System.out.println(opt.getText()));
// Custom dropdown (React/Angular)
driver.findElement(By.id("custom-dropdown")).click();
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".dropdown-options")));
driver.findElements(By.cssSelector(".dropdown-option"))
.stream().filter(e -> e.getText().equals("India"))
.findFirst().ifPresent(WebElement::click); -- Find duplicate emails with count
SELECT email, COUNT(*) as cnt
FROM users
GROUP BY email
HAVING COUNT(*) > 1
ORDER BY cnt DESC;
-- Find all user records that are duplicates
SELECT * FROM users
WHERE email IN (
SELECT email FROM users
GROUP BY email
HAVING COUNT(*) > 1
)
ORDER BY email;
-- Delete duplicates keeping lowest id
DELETE FROM users
WHERE id NOT IN (
SELECT MIN(id) FROM users GROUP BY email
); // Bug Report Template: // Title: [Component] Brief description of issue // Severity: Critical/Major/Minor/Trivial // Priority: High/Medium/Low // // Environment: // OS: Windows 11 / macOS 14 / iOS 17 // Browser: Chrome 120 / Safari 17 // App Version: v2.4.1 // // Steps to Reproduce: // 1. Navigate to https://app.example.com/login // 2. Enter email: test@gmail.com // 3. Enter password: Test@123! // 4. Click "Sign In" button // // Expected: User is logged in and redirected to dashboard // Actual: Error "Invalid credentials" shown despite correct credentials // // Frequency: 100% reproducible // Attachment: screenshot_login_error.png
Cognizant Interview Process
IT Services · MNC · Chennai / Pan-India · 2–3 Rounds
🔬 Technical Interview
Cognizant Technical: QA concepts, manual testing, basic automation, and project discussion. Be ready to discuss a full testing project end-to-end. Cognizant values structured communication.
// Example: password length must be 8-20 characters // EP Partitions: // Valid: 8–20 chars → test "Password1" (9 chars) // Too short: 1–7 chars → test "Pass" (4 chars) // Too long: >20 chars → test 25-char string // BVA (at boundaries): // 7 chars → INVALID (just below lower bound) // 8 chars → VALID (lower bound) // 9 chars → VALID (just above lower bound) // 20 chars → VALID (upper bound) // 21 chars → INVALID (just above upper bound)
public void findPairs(int[] arr, int target) {
Set<Integer> seen = new HashSet<>();
Set<String> printed = new HashSet<>(); // avoid duplicate pairs
for (int n : arr) {
int complement = target - n;
if (seen.contains(complement)) {
// Create canonical pair representation (smaller first)
String pair = Math.min(n, complement) + "+" + Math.max(n, complement);
if (printed.add(pair)) {
System.out.println(complement + " + " + n + " = " + target);
}
}
seen.add(n);
}
}
// [1,2,3,4,5,6] target=7 → (1,6), (2,5), (3,4)
// [1,1,2,4,4] target=5 → (1,4) -- GROUP BY + HAVING: departments with more than 3 employees
SELECT department, COUNT(*) as emp_count, AVG(salary) as avg_salary
FROM employees
GROUP BY department
HAVING COUNT(*) > 3
ORDER BY avg_salary DESC;
-- Window function: rank employees by salary within department
SELECT name, department, salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_in_dept,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rank,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num,
SUM(salary) OVER (PARTITION BY department) AS dept_total_salary
FROM employees;
-- Running total of sales by date
SELECT date, amount,
SUM(amount) OVER (ORDER BY date) AS running_total
FROM sales; // Answer template: // "I tested a [domain] application using [tech stack]. // My responsibilities included [specific tasks]. // Testing types: functional (Selenium), API (REST Assured), performance (JMeter). // Key challenge: [specific challenge]. // Resolution: [how I solved it]. // Outcome: found [N] defects, [X]% escaped to production (down from [Y]%). // What I'd do differently: [specific improvement]."
HCL Technologies Interview Process
IT Services · MNC · Noida HQ · 2–3 Rounds
🔬 Technical Interview
HCL Technical: QA theory, manual testing, basic automation, and SQL. HCL appreciates candidates who ask good questions about the role and domain. Show genuine interest in their specific industry verticals (banking, telecom, healthcare).
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next; // save next
curr.next = prev; // reverse pointer
prev = curr; // advance prev
curr = next; // advance curr
}
return prev; // prev is now the new head
}
// Test cases to mention:
// TC1: [1,2,3,4,5] → [5,4,3,2,1] (normal case)
// TC2: [1,2] → [2,1] (two elements)
// TC3: [1] → [1] (single element)
// TC4: null → null (empty list)
// TC5: [1,1,1] → [1,1,1] (all same values) -- Using DENSE_RANK (handles ties correctly)
SELECT department, name, salary, rank_in_dept
FROM (
SELECT
department,
name,
salary,
DENSE_RANK() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS rank_in_dept
FROM employees
) ranked
WHERE rank_in_dept <= 3
ORDER BY department, rank_in_dept;
-- If two employees have the same salary, DENSE_RANK gives them same rank
-- [VP: 100K, 100K, 90K] → ranks 1,1,2 (two people tied at rank 1)
-- vs RANK: 1,1,3 (skips rank 2) // Basic REST Assured example
given()
.baseUri("https://api.example.com")
.header("Authorization", "Bearer " + token)
.when()
.get("/users/123")
.then()
.statusCode(200)
.header("Content-Type", containsString("application/json"))
.body("id", equalTo(123))
.body("name", notNullValue())
.body("email", matchesPattern("[^@]+@[^@]+\.[^@]+"))
.time(lessThan(500L)); // response time SLA public class LoginPage {
private final WebDriver driver;
@FindBy(id="email") private WebElement emailField;
@FindBy(id="password") private WebElement passwordField;
@FindBy(id="loginBtn") private WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public DashboardPage login(String email, String password) {
emailField.sendKeys(email);
passwordField.sendKeys(password);
loginButton.click();
return new DashboardPage(driver); // returns next page
}
}
// Test class - clean and readable
@Test
public void validLogin_ShouldShowDashboard() {
DashboardPage dashboard = loginPage.login("user@test.com", "Pass123");
Assert.assertTrue(dashboard.isDisplayed()); // assertion in test, not in page
}