🎯 APPIUM + TESTNG + MOBILE AUTOMATION -
COMPLETE INTERVIEW GUIDE 2024
100% CRACK-WORTHY | ZERO CONFUSION | BABY-FRIENDLY
EXPLANATIONS
✅ TABLE OF CONTENTS
1. Foundation Basics (No Prior Knowledge Needed)
2. Appium Fundamentals Q&A
3. Framework Architecture Q&A
4. TestNG Q&A
5. POM (Page Object Model) Q&A
6. Real-World Scenarios
7. BDD WITH CUCUMBER Q&A
8. Payment & OTP Automation
9. Complete Code Examples
[Link] Confidence Boosters
📚 SECTION 1: FOUNDATION BASICS
For Complete Beginners (Explain Like I'm 5)
What is Mobile Automation?
WITHOUT AUTOMATION:
Employee: "I need to test the Paytm app"
Task: Tap button 500 times, check result 500 times
Time: 10 hours per day
Accuracy: 50% (human mistakes)
WITH AUTOMATION:
Robot: *Taps button 500 times automatically*
Robot: *Checks results automatically*
Time: 5 minutes
Accuracy: 100% (no mistakes)
Answer for Interview: "Mobile automation is using robots (code) to test apps automatically
instead of humans clicking buttons manually. It's faster, more reliable, and cheaper in long run."
What is Appium? (Simplest Explanation)
Think of it like:
WhatsApp Desktop = Appium
Your Android Phone = Your App
Just like WhatsApp Desktop controls your phone from laptop,
Appium controls your Android phone from laptop for testing.
Answer for Interview: "Appium is an open-source automation tool that lets us control Android and
iOS apps from a computer. Like a robot sitting next to the phone, tapping buttons, typing text, and
checking results automatically."
Why Appium and Not Other Tools?
Other tools like Calabash, Espresso → Only for Android
Other tools like XCUITest → Only for iOS
Appium → Works for BOTH Android AND iOS with same code ✓
Open source → FREE ✓
Write in Java, Python, JavaScript → Your choice ✓
Industry standard → Everyone uses it ✓
Emulator vs Real Device
EMULATOR (Virtual Phone)
├─ ✓ Free
├─ ✓ Fast on PC
├─ ✓ Easy to reset
├─ ✓ Easy to install new versions
└─ ✗ Camera not realistic
└─ ✗ GPS simulation not realistic
REAL DEVICE (Actual Phone)
├─ ✓ Camera works perfectly
├─ ✓ GPS works perfectly
├─ ✓ Touch works naturally
├─ ✓ Hardware buttons work
└─ ✗ Slower than emulator
└─ ✗ Need to charge battery
└─ ✗ Physical device needed
🔥 SECTION 2: APPIUM FUNDAMENTALS Q&A
Q1: What are "Desired Capabilities"?
Simple Answer: "Desired Capabilities are like a form you fill before starting. You tell Appium: 'I
want Android, version 13, this app package, this activity.' Without it, Appium doesn't know which
phone or app to use."
Code Example:
UiAutomator2Options options = new UiAutomator2Options()
.setDeviceName("Pixel_7") ← Tell Appium: which phone
.setPlatformVersion("13.0") ← Tell Appium: Android version
.setAppPackage("[Link]") ← Tell Appium: which app
.setAppActivity(".MainActivity") ← Tell Appium: which screen to open
.autoGrantPermissions(); ← Tell Appium: auto-allow permissions
Interview Answer: "Desired Capabilities are settings that tell Appium which device, which app,
and which Android version to use. They're like coordinates telling a robot: 'Go to this phone, launch
this app.'"
Q2: What is appPackage and appActivity?
Baby Explanation:
appPackage = Your house address ([Link])
appActivity = Which room to enter in the house (.MainActivity)
Appium: "I need to go to house at address [Link]"
Appium: "And when I enter, go to room called MainActivity"
How to Find Them:
# Connect phone with USB
# Run this command:
adb shell dumpsys window | grep mCurrentFocus
# Output:
mCurrentFocus=Window{abc123 u0 [Link]/.MainActivity}
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^
appPackage appActivity
Interview Answer: "appPackage is the unique identifier of the app (like Aadhar number for your
app). appActivity is the screen name that opens when the app launches. We find them using 'adb
shell dumpsys window' command."
Q3: What is UiAutomator2?
Simple Answer: "UiAutomator2 is the engine that Appium uses to control Android phones. Think
of it as Appium's brain that understands Android."
Code Context:
UiAutomator2Options options = new UiAutomator2Options()
.setAutomationName("UiAutomator2") ← This is the engine
// Rest of config...
Other Engines:
UiAutomator2 → For Android (MOST COMMON, USE THIS)
XCUITest → For iOS
Both are built into Appium by default.
Interview Answer: "UiAutomator2 is the automation engine for Android. It's the mechanism that
Appium uses to interact with Android elements. Without specifying it, Appium doesn't know how
to control the device."
Q4: How Does Appium Actually Work?
Step by Step:
Step 1: Your Test Code
↓
"[Link]([Link]('button')).click()"
↓
Step 2: Appium Server (on laptop at [Link]:4723)
↓
"Find element with ID 'button' on the phone"
↓
Step 3: Appium Server sends to UiAutomator2 (on phone)
↓
"UiAutomator2, find element with ID 'button'"
↓
Step 4: UiAutomator2 searches Android UI on phone
↓
"Found it! Location: (100, 200)"
↓
Step 5: Appium sends back response
↓
"Element found at (100, 200)"
↓
Step 6: Your code taps it
↓
BUTTON TAPPED ✓
Interview Answer: "Appium works in 3 layers: Your test code sends commands to Appium Server,
which sends instructions to UiAutomator2 on the device, which interacts with the actual Android
UI. Response comes back the same way."
Q5: What is [Link]?
Simple Answer:
Your Code → ([Link]:4723) → Appium Server
([Link] = Your own computer)
(4723 = Port number where Appium listens)
In Code:
URL appiumServerUrl = new URL("[Link]
AndroidDriver driver = new AndroidDriver(appiumServerUrl, options);
What if you use Cloud?
// Local
URL url = new URL("[Link]
// BrowserStack (Cloud)
URL url = new URL("[Link]
// SauceLabs (Cloud)
URL url = new
URL("[Link]
Interview Answer: "[Link] is the address where Appium server listens for commands.
By default it's localhost:4723 (your own computer). For cloud testing, it's the URL of cloud service
like BrowserStack."
Q6: What is UDID?
Baby Explanation:
Your Phone Serial Number = UDID
Just like each phone has a unique serial number,
UDID uniquely identifies a device.
How to Find:
adb devices
Output:
emulator-5554 ← UDID of emulator
[Link]:5555 ← UDID of real device
In Code:
.setUdid("emulator-5554") ← Which phone to use
Interview Answer: "UDID (Unique Device ID) uniquely identifies a device. Find it using 'adb
devices' command. It's required in capabilities to tell Appium which specific device to use when
multiple devices are connected."
Q7: What is noReset, fullReset, and resetType?
Explanation with Example:
Scenario: You have Paytm app already installed on phone
With your login data and cached information
OPTION 1: noReset = true
├─ Appium: "Keep everything as is"
├─ App opens with old data
├─ Your login still there
├─ Tests run faster
└─ USE: When testing specific feature (NOT app startup)
OPTION 2: fullReset = true
├─ Appium: "Delete app completely, reinstall it"
├─ App opens fresh like first time
├─ No old data
├─ Tests are clean but SLOW
└─ USE: When testing app installation or fresh start
OPTION 3: Default (no setting)
├─ Appium: "Clear app cache but keep app"
├─ Middle ground
└─ Most balanced option
In Code:
// Option 1: Keep app as is
.noReset()
// Option 2: Delete and reinstall app
.fullReset()
// Option 3: Clear cache only
// (just don't set any reset option)
Interview Answer: "noReset keeps the app unchanged - useful for quick tests. fullReset deletes and
reinstalls the app - useful for clean slate testing. Choose based on whether you need old data or
not."
Q8: What is autoGrantPermissions?
Simple Scenario:
App asks: "Can I use your Camera?"
├─ Without autoGrantPermissions:
│ └─ Popup appears on screen
│ └─ Test must find and click "Allow" button
│ └─ Slow and error-prone
│
└─ With autoGrantPermissions:
└─ Popup auto-clicks "Allow"
└─ Test never sees the popup
└─ Test runs faster
In Code:
.setAutoGrantPermissions(true) ← Auto-allow all permission popups
Interview Answer: "autoGrantPermissions tells Appium to automatically click 'Allow' on
permission popups. Without it, tests have to find and click the popup manually."
🎭 SECTION 3: FRAMEWORK ARCHITECTURE Q&A
Q9: What is Page Object Model (POM)?
Real-Life Analogy:
WITHOUT POM (Bad way):
Test File 1: "Click button at 100,200"
Test File 2: "Click button at 100,200"
Test File 3: "Click button at 100,200"
Test File 4: "Click button at 100,200"
Button changes location to 150,250:
├─ Update Test File 1 ✓
├─ Update Test File 2 ✓
├─ Update Test File 3 ✓
├─ Update Test File 4 ✓
Time wasted: 1 hour ❌
WITH POM (Good way):
[Link]:
private By loginButton = [Link]("button")
public void clickLogin() {
[Link](loginButton).click()
}
Test File 1: [Link]()
Test File 2: [Link]()
Test File 3: [Link]()
Test File 4: [Link]()
Button changes location to 150,250:
├─ Update [Link] only ✓
Time wasted: 2 minutes ✓
Baby Explanation: "POM is like making a restaurant menu. Instead of telling customers 'go to
shelf 3, pick item from position 5', you create a menu saying 'order Coffee' or 'order Tea'. When
items move, only menu changes, not all customer instructions."
Interview Answer: "Page Object Model organizes locators and methods into one class per screen.
Tests call page methods instead of writing locators. If locators change, update one file instead of 50
test files."
Q10: What is BasePage?
Simple Answer:
// [Link] = Common stuff for ALL pages
public class BasePage {
public BasePage() {
// Initialize page factory for all pages
[Link](
new AppiumFieldDecorator(driver,
[Link](15)),
this);
}
}
// Every page extends BasePage
public class LoginPage extends BasePage {
// Has access to driver and all common stuff
}
public class HomePage extends BasePage {
// Has access to driver and all common stuff
}
Why? "Instead of repeating PageFactory code in every page, BasePage has it once. Every page
class extends BasePage and automatically gets this initialization."
Interview Answer: "BasePage is a parent class containing common functionality for all page
objects. Every page class extends it. This prevents code duplication."
Q11: What is AppiumFieldDecorator?
Baby Explanation:
WITHOUT AppiumFieldDecorator:
@Test
public void test() {
WebElement button = [Link]([Link]("btn"))
[Link]()
}
↑ Every test has to find element
WITH AppiumFieldDecorator (POM Way):
public class LoginPage {
@AndroidFindBy(id = "btn")
private WebElement button; ← Element found automatically!
public void clickLogin() {
[Link]() ← Just use it!
}
}
↑ Element is found and ready to use
Interview Answer: "AppiumFieldDecorator is Appium's version of PageFactory. It automatically
finds and initializes elements marked with @AndroidFindBy annotation without needing explicit
findElement() calls."
Q12: What is ThreadLocal in DriverManager?
Scenario:
WITHOUT ThreadLocal (WRONG):
Test 1 (on Device 1): Uses driver
Test 2 (on Device 2): Uses same driver
↓
CONFLICT ❌
Both try to use same driver
Tests fail
WITH ThreadLocal (CORRECT):
Test 1 (on Device 1): driver = driver1
Test 2 (on Device 2): driver = driver2
↓
Each test has OWN driver ✓
No conflict
Tests pass ✓
Code:
public final class DriverManager {
private static final ThreadLocal<AppiumDriver> driverThread
= new ThreadLocal<>();
public static void setDriver(AppiumDriver driver) {
[Link](driver); ← Each thread gets its own
}
public static AppiumDriver getDriver() {
return [Link](); ← Get YOUR thread's driver
}
}
Baby Explanation: "ThreadLocal is like giving each student their own pencil. Student A has pencil
A, Student B has pencil B. No conflict. Without ThreadLocal, all students share one pencil and fight
over it."
Interview Answer: "ThreadLocal ensures each test thread gets its own driver instance. Essential
for parallel test execution. Without it, multiple tests on different devices would share the same
driver and crash."
Q13: What is @AndroidFindBy annotation?
Baby Explanation:
// BAD WAY (Annoying):
public class LoginPage {
public void clickLogin() {
By loginButton = [Link]("[Link]:id/login_btn")
[Link](loginButton).click()
}
}
// GOOD WAY (Clean):
public class LoginPage {
@AndroidFindBy(id = "[Link]:id/login_btn")
private WebElement loginButton;
public void clickLogin() {
[Link]() ← Much cleaner!
}
}
How it Works: "@AndroidFindBy tells PageFactory: 'Before test runs, find this element using this
locator, and put it in this variable. I'll use it when needed.'"
Interview Answer: "@AndroidFindBy is an annotation that tells AppiumFieldDecorator to
automatically find and initialize elements. Elements are found before test runs, not when test calls
them."
Q14: Locator Strategy - Which to Use?
Priority Order (ALWAYS Follow This):
1️⃣ RESOURCE-ID (Best - Use First)
@AndroidFindBy(id = "[Link]:id/search_button")
✓ Unique
✓ Fastest
✓ Reliable
✓ Recommended
2️⃣ ACCESSIBILITY-ID (Second Choice)
@AndroidFindBy(accessibility = "Search")
✓ Good for accessibility testing
✓ Reliable if set by developers
3️⃣ XPATH (Third Choice - Use Only When Above Fail)
@AndroidFindBy(xpath = "//[Link][@text='Search']")
✗ Slower
✗ Breaks if UI changes
✗ Last resort
4️⃣ CLASS-NAME (Avoid)
@AndroidFindBy(className = "[Link]")
✗ Not specific
✗ Multiple elements might match
✗ Use only if nothing else works
How to Find Resource-ID:
# Step 1: Start Appium Server
appium
# Step 2: Open Appium Inspector (Desktop App)
# Step 3: Enter capabilities → Start Session
# Step 4: On phone screen, tap element you want
# Step 5: Right panel shows resource-id like:
resource-id: [Link]:id/login_btn
# Step 6: Copy and use in @AndroidFindBy
@AndroidFindBy(id = "[Link]:id/login_btn")
Interview Answer: "Use resource-id first (it's unique and fastest). If not available, use
accessibility-id. Use xpath only as last resort because it breaks easily when UI changes."
🧪 SECTION 4: TESTNG Q&A
Q15: What is TestNG?
Simple Answer: "TestNG is a testing framework that helps organize and run tests. It's like a
manager that decides which test to run, when to run it, and what to do if it fails."
Without TestNG:
// Manual test running (BAD)
Test1 test1 = new Test1();
[Link]();
[Link]();
[Link]();
Test2 test2 = new Test2();
[Link]();
[Link]();
[Link]();
Test3 test3 = new Test3();
[Link]();
[Link]();
[Link]();
With TestNG:
// TestNG runs everything automatically (GOOD)
@BeforeMethod
public void setup() { /* code */ }
@Test
public void testLogin() { /* code */ }
@Test
public void testSearch() { /* code */ }
@Test
public void testPayment() { /* code */ }
@AfterMethod
public void teardown() { /* code */ }
// Just run: mvn test
// TestNG handles everything automatically ✓
Interview Answer: "TestNG is a Java testing framework that automatically runs test methods,
manages setup/teardown, supports data-driven testing, parallel execution, and generates reports."
Q16: What are TestNG Annotations?
Visual Map:
┌─────────────────────────────────────────────────┐
│ TEST EXECUTION FLOW │
├─────────────────────────────────────────────────┤
│ │
│ @BeforeSuite (Runs ONCE at very start) │
│ ↓ │
│ @BeforeTest (Runs ONCE per <test> in XML) │
│ ↓ │
│ @BeforeClass (Runs ONCE per class) │
│ ↓ │
│ @BeforeMethod (Runs BEFORE EVERY test) │
│ ↓ │
│ @Test : testLogin() │
│ ↓ │
│ @AfterMethod (Runs AFTER EVERY test) │
│ ↓ │
│ @BeforeMethod (Again for next test) │
│ ↓ │
│ @Test : testSearch() │
│ ↓ │
│ @AfterMethod (Again) │
│ ↓ │
│ @AfterClass (Runs ONCE per class) │
│ ↓ │
│ @AfterTest (Runs ONCE per <test> in XML) │
│ ↓ │
│ @AfterSuite (Runs ONCE at very end) │
│ │
└─────────────────────────────────────────────────┘
Practical Example:
public class LoginTest {
@BeforeSuite
public void suiteSetup() {
[Link]("Suite started")
// Initialize reports, config, etc
}
@BeforeMethod
public void methodSetup() {
[Link]("Test starting")
// Launch app, initialize driver
}
@Test
public void testLogin() {
[Link]("Running login test")
}
@Test
public void testLogout() {
[Link]("Running logout test")
}
@AfterMethod
public void methodTeardown() {
[Link]("Test finished")
// Close app, quit driver
}
@AfterSuite
public void suiteTeardown() {
[Link]("Suite finished")
// Flush reports, send notifications
}
}
/* OUTPUT:
Suite started
Test starting
Running login test
Test finished
Test starting
Running logout test
Test finished
Suite finished
*/
Interview Answer: "@BeforeSuite/AfterSuite run once per suite. @BeforeClass/AfterClass run
once per class. @BeforeMethod/AfterMethod run before/after EVERY test. Use them for setup
(driver init) and teardown (driver quit)."
Q17: What is @DataProvider?
Real-Life Scenario:
WITHOUT DataProvider (Boring):
@Test
public void testLoginWithValidCredentials() {
[Link]("user1@[Link]", "pass123")
[Link]([Link]())
}
@Test
public void testLoginWithValidCredentials2() {
[Link]("user2@[Link]", "pass456")
[Link]([Link]())
}
@Test
public void testLoginWithValidCredentials3() {
[Link]("user3@[Link]", "pass789")
[Link]([Link]())
}
// Repeated same test 3 times ❌
WITH DataProvider (Smart):
@DataProvider(name = "validUsers")
public Object[][] validUsers() {
return new Object[][] {
{"user1@[Link]", "pass123"},
{"user2@[Link]", "pass456"},
{"user3@[Link]", "pass789"}
}
}
@Test(dataProvider = "validUsers")
public void testLogin(String email, String password) {
[Link](email, password)
[Link]([Link]())
}
// Same test, runs 3 times with different data ✓
JSON Data Approach (Professional):
// [Link]
{
"validUsers": [
{"email": "user1@[Link]", "password": "pass123"},
{"email": "user2@[Link]", "password": "pass456"},
{"email": "user3@[Link]", "password": "pass789"}
]
}
// Test reads JSON and runs for each entry
@DataProvider(name = "validUsers")
public Object[][] readFromJSON() {
// Read JSON file and convert to 2D array
// Return array
}
@Test(dataProvider = "validUsers")
public void testLogin(String email, String password) {
// Same test code
}
Interview Answer: "@DataProvider feeds different test data to the same test method. Instead of
writing 10 similar tests, write 1 test and use DataProvider to run it 10 times with different data."
Q18: Assertions - Hard vs Soft
Difference:
HARD ASSERT (Assert class):
├─ When assertion fails → TEST STOPS IMMEDIATELY
├─ Use: For critical checks
├─ Example: "If login fails, don't proceed"
└─ Code:
[Link]([Link]())
SOFT ASSERT (SoftAssert class):
├─ When assertion fails → TEST CONTINUES
├─ Collects all failures
├─ Reports all at end
├─ Use: For multiple checks on one screen
└─ Code:
SoftAssert soft = new SoftAssert()
[Link]([Link]())
[Link](title, "Home")
[Link]() // Report all failures
Practical Example:
// Scenario: Testing home screen with multiple elements
// BAD: Using hard assert (stops at first failure)
@Test
public void testHomeScreen() {
HomePage home = new HomePage()
[Link]([Link]()) // Fails → STOP
[Link]([Link]()) // Never runs
[Link]([Link]()) // Never runs
}
// Only reports 1 failure ❌
// GOOD: Using soft assert (reports all failures)
@Test
public void testHomeScreen() {
HomePage home = new HomePage()
SoftAssert soft = new SoftAssert()
[Link]([Link]()) // Fails → Continue
[Link]([Link]()) // Fails → Continue
[Link]([Link]()) // Passes
[Link]() // Report all 3 results ✓
}
// Reports all failures ✓
Interview Answer: "Hard Assert stops test at first failure. Use for critical checks. Soft Assert
continues and reports all failures together. Use for verifying multiple things on one screen."
Q19: What is @Test attributes?
Common Attributes:
@Test(
description = "Verify user can login with valid credentials",
groups = {"smoke", "regression"}, // Run specific test groups
dependsOnMethods = {"testLogin"}, // Run only if testLogin passes
dataProvider = "validUsers", // Use data provider
retryAnalyzer = [Link], // Retry if fails
invocationCount = 2, // Run this test 2 times
enabled = true // Enable/disable test
)
public void testLogin() {
// Test code
}
Interview Answer: "@Test attributes customize test behavior. description explains what test does.
groups organize tests (smoke/regression). dependsOnMethods runs test only if another passes.
dataProvider feeds different data."
Q20: TestNG XML - How to Control Test Execution
Example XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "[Link]
<suite name="Regression Suite" verbose="1">
<!-- Listeners for reports and screenshots -->
<listeners>
<listener class-name="[Link]"/>
</listeners>
<!-- Define specific tests to run -->
<test name="Login Tests">
<!-- Only run tests with "smoke" group -->
<groups>
<run>
<include name="smoke"/>
</run>
</groups>
<!-- Run all test classes in smoke package -->
<packages>
<package name="[Link]"/>
</packages>
</test>
<test name="Search Tests">
<groups>
<run>
<include name="regression"/>
</run>
</groups>
<packages>
<package name="[Link]"/>
</packages>
</test>
</suite>
Run Different Suites:
# Run smoke only
mvn test -Dsuite=testng/[Link]
# Run regression
mvn test -Dsuite=testng/[Link]
# Run parallel
mvn test -Dsuite=testng/[Link]
Interview Answer: "TestNG XML defines which tests to run. You can include/exclude test groups,
run specific packages, set parallel execution, and attach listeners. Different XML files = different
test suites."
💰 SECTION 5: REAL-WORLD PAYMENT & OTP
SCENARIOS
Q21: Payment Flow - Complete End-to-End
User Journey:
User
├─ Adds items to cart
│ └─ [Item 1] [Item 2] [Item 3]
│
├─ Goes to checkout
│ └─ Sees: Cart Total: $100
│
├─ Enters shipping address
│ └─ "123 Main Street, New York"
│
├─ Selects shipping method
│ └─ "Express - 2 Days" = $10
│ └─ New Total: $110
│
├─ Payment screen
│ └─ Selects "Credit Card"
│ └─ Enters card: 4111 1111 1111 1111
│ └─ Expiry: 12/25
│ └─ CVV: 123
│
├─ Taps "Pay Now"
│ └─ [Connecting to payment gateway...]
│
├─ Payment gateway processes
│ └─ [Processing...]
│
└─ Order confirmation
└─ "Order #12345 Confirmed"
└─ "Email sent to user@[Link]"
Complete Test Code:
@Test(description = "End-to-end payment flow")
public void testCompletePaymentFlow() {
// ARRANGE - Setup
HomePage homePage = new HomePage();
// ACT - Add to cart
[Link]("Laptop")
ProductPage product = [Link]("Dell Laptop")
CartPage cart = [Link]()
// Verify item in cart
[Link]([Link]("Dell Laptop"))
// Go to checkout
CheckoutPage checkout = [Link]()
// Enter shipping address
[Link]("123 Main Street")
[Link]("New York")
// Select shipping method
[Link]("Express")
String totalBeforePayment = [Link]() // "$110"
// Go to payment
PaymentPage payment = [Link]()
// Enter payment details
[Link]("Credit Card")
[Link]("4111111111111111")
[Link]("12/25")
[Link]("123")
// Tap Pay
[Link]()
// Wait for processing (payment takes time)
new WebDriverWait(driver, [Link](30))
.until([Link](
[Link]("order_confirmation_page")))
// ASSERT - Verify success
OrderConfirmationPage confirmation = new OrderConfirmationPage()
[Link]([Link]())
[Link]([Link]())
[Link]([Link]().contains("110"))
}
Interview Answer: "For payment flows I test the complete user journey: add items → checkout →
address → shipping → payment details → confirmation. I verify order total, order number, and
confirmation message."
Q22: Payment Gateway Failures & Retries
Scenario: What if payment fails?
User taps "Pay"
↓
Payment gateway responds: "Service Unavailable"
↓
User should see: "Payment failed. Retry?"
↓
User taps "Retry"
↓
Payment gateway: Now working ✓
↓
Order confirmed ✓
Test Code:
@Test(description = "Payment retry on gateway failure")
public void testPaymentRetryOnGatewayFailure() {
PaymentPage payment = new PaymentPage()
// Mock API to fail first time
mockPaymentGateway([Link])
[Link]("4111111111111111")
[Link]("12/25")
[Link]("123")
// First attempt fails
[Link]()
// Wait for error message
new WebDriverWait(driver, [Link](10))
.until([Link](
[Link]("error_message")))
// Verify error shown
[Link]([Link]())
[Link](
[Link]().contains("Service Unavailable"))
// Verify Retry button visible
[Link]([Link]())
// Mock API to now succeed
mockPaymentGateway([Link])
// Retry payment
[Link]()
// Wait for confirmation
new WebDriverWait(driver, [Link](30))
.until([Link](
[Link]("order_confirmation_page")))
// Verify success
OrderConfirmationPage confirmation = new OrderConfirmationPage()
[Link]([Link]())
}
Interview Answer: "For payment failures I mock the payment gateway to fail first, verify error is
shown and retry button is visible, then mock success and verify retry works."
Q23: Payment Timeout Handling
Problem:
User taps Pay
Payment gateway is slow (15 seconds)
Test timeout is 10 seconds
Test fails incorrectly ❌
Solution:
// [Link]
[Link]=10 (for normal operations)
[Link]=30 (for payment - give more time)
[Link]=60 (for OTP - give most time)
// Test code
@Test
public void testPaymentWithTimeout() {
PaymentPage payment = new PaymentPage()
[Link]("4111111111111111")
[Link]("12/25")
[Link]("123")
// Pay button tap
[Link]()
// Use LONGER timeout for payment
int paymentTimeout = [Link]("[Link]", 30)
new WebDriverWait(driver, [Link](paymentTimeout))
.until([Link](
[Link]("order_confirmation_page")))
// Verify confirmation
OrderConfirmationPage confirmation = new OrderConfirmationPage()
[Link]([Link]())
}
Interview Answer: "For payment timeouts I use longer wait times specifically for payment pages.
Configure [Link]=30 in properties and use it for payment operations."
Q24: OTP (One Time Password) Testing
What is OTP?
User enters phone: +91 9876543210
System sends: "Your OTP is 123456"
User enters: 123456
System verifies: "Correct! Login successful"
Test Scenarios:
Scenario 1: Valid OTP
├─ System sends OTP
├─ User enters correct OTP
├─ Login successful ✓
Scenario 2: Wrong OTP (user makes typo)
├─ System sends OTP: 123456
├─ User enters: 654321 (wrong)
├─ System shows: "Invalid OTP"
├─ Allow retry
Scenario 3: OTP Expired
├─ System sends OTP (valid for 5 min)
├─ User waits 6 minutes
├─ User enters OTP
├─ System shows: "OTP Expired"
├─ Show "Resend OTP" button
Scenario 4: Max Attempts Exceeded
├─ System sends OTP: 123456
├─ User tries 3 times with wrong OTP
├─ After 3 failures: "Account locked for 30 minutes"
├─ Block further attempts
Test Code - Valid OTP:
@Test(description = "Valid OTP login")
public void testValidOTPLogin() {
LoginPage login = new LoginPage()
[Link]("+91 9876543210")
[Link]()
// Verify OTP screen appears
OTPPage otp = new OTPPage()
[Link]([Link]())
// In test env, OTP is fixed: 123456
[Link]("123456")
[Link]()
// Verify login successful
HomePage home = new HomePage()
[Link]([Link]())
}
Test Code - Wrong OTP:
@Test(description = "Wrong OTP shows error")
public void testWrongOTPError() {
LoginPage login = new LoginPage()
[Link]("+91 9876543210")
[Link]()
OTPPage otp = new OTPPage()
// Enter wrong OTP
[Link]("999999")
[Link]()
// Verify error
[Link]([Link]())
[Link](
[Link]().contains("Invalid OTP"))
// Verify user can retry
[Link]([Link]())
}
Test Code - OTP Expiry:
@Test(description = "OTP expires after 5 minutes")
public void testOTPExpiry() {
LoginPage login = new LoginPage()
[Link]("+91 9876543210")
[Link]()
// Verify OTP valid for 5 min
OTPPage otp = new OTPPage()
[Link]([Link]("5:00"))
// Mock system time to advance 6 minutes
mockSystemTime("+6 minutes")
// Try to enter OTP
[Link]("123456")
[Link]()
// Verify expiry error
[Link]([Link]())
[Link](
[Link]().contains("OTP Expired"))
// Verify Resend button available
[Link]([Link]())
}
Test Code - Max Attempts:
@Test(description = "Account locks after 3 wrong OTP attempts")
public void testOTPMaxAttemptsLockout() {
LoginPage login = new LoginPage()
[Link]("+91 9876543210")
[Link]()
OTPPage otp = new OTPPage()
// Wrong attempt 1
[Link]("111111")
[Link]()
[Link]([Link]())
[Link]([Link](), "2 attempts left")
// Wrong attempt 2
[Link]()
[Link]("222222")
[Link]()
[Link]([Link]())
[Link]([Link](), "1 attempt left")
// Wrong attempt 3
[Link]()
[Link]("333333")
[Link]()
// Account should lock
[Link]([Link]())
[Link](
[Link]().contains("Account locked for 30 minutes"))
// OTP input field should be disabled
[Link]([Link]())
}
Interview Answer: "For OTP testing I test valid entry, wrong entry, expiry, and lockout. Use fixed
OTP in test environment for reliability. Mock system time to test expiry. Verify error messages and
button states."
Q25: OTP Resend & Rate Limiting
Scenario:
User clicks "Resend OTP" → New OTP sent
But what if user clicks "Resend" 10 times in 1 second?
System should limit: "Wait 60 seconds before resending"
Test Code:
@Test(description = "OTP resend with rate limiting")
public void testOTPResendRateLimiting() {
LoginPage login = new LoginPage()
[Link]("+91 9876543210")
[Link]()
OTPPage otp = new OTPPage()
// First resend - should work
[Link]()
[Link]([Link]())
// Immediately tap resend 4 more times
for (int i = 0; i < 4; i++) {
try {
[Link]()
} catch (Exception e) {
// After 1-2 resendsystem rate limits
}
}
// After rate limit, should show error
[Link]([Link]())
[Link](
[Link]()
.contains("Please wait 60 seconds"))
}
Interview Answer: "For resend rate limiting I test that first resend works, but rapid resends are
blocked. Verify 'wait X seconds' message appears after limit exceeded."
🌈 SECTION 6: BDD WITH CUCUMBER
Q26: What is BDD and Why Use It?
Simple Explanation:
WITHOUT BDD (Tech talk):
Test: "Verify login with valid credentials populates JWT token"
WITH BDD (Business language):
Scenario: User should be able to login
Given User is on login screen
When User enters valid credentials
And User taps login button
Then User should see home screen
^ Anyone can read it (QA, Developer, Manager, Business person)
Baby Explanation: "BDD writes tests in English-like language instead of code. Your grandma can
read it! It bridges gap between non-technical people and technical tests."
Interview Answer: "BDD (Behavior Driven Development) writes tests in plain English using
Cucumber. Non-technical people can read and understand what tests do. It improves
communication between QA, Devs, and Business."
Q27: Cucumber + Appium Setup
Step 1: Add Dependencies to [Link]
<dependencies>
<!-- Cucumber -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.14.0</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>cucumber-testng</artifactId>
<version>7.14.0</version>
</dependency>
<!-- Appium -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>java-client</artifactId>
<version>9.2.3</version>
</dependency>
<!-- Rest of dependencies... -->
</dependencies>
Step 2: Create Feature File
File: src/test/resources/features/[Link]
Feature: User Login Functionality
Scenario: User successfully logs in with valid credentials
Given User is on login page
When User enters email "user@[Link]"
And User enters password "Pass123"
And User taps login button
Then User should see home page
Scenario: User sees error with invalid credentials
Given User is on login page
When User enters email "wrong@[Link]"
And User enters password "WrongPass"
And User taps login button
Then User should see error message "Invalid credentials"
Step 3: Create Step Definitions
// File: [Link]
public class LoginStepDefinitions {
private AppiumDriver driver;
private LoginPage loginPage;
private HomePage homePage;
@Before
public void setup() {
// Initialize driver
driver = [Link]()
loginPage = new LoginPage()
}
@Given("User is on login page")
public void userOnLoginPage() {
// Verify login page is displayed
[Link]([Link]())
}
@When("User enters email {string}")
public void userEntersEmail(String email) {
[Link](email)
}
@When("User enters password {string}")
public void userEntersPassword(String password) {
[Link](password)
}
@When("User taps login button")
public void userTapsLogin() {
homePage = [Link]()
}
@Then("User should see home page")
public void verifyHomePageDisplayed() {
[Link]([Link]())
}
@Then("User should see error message {string}")
public void verifyErrorMessage(String expectedMessage) {
[Link](
[Link]().contains(expectedMessage))
}
@After
public void teardown() {
[Link]()
}
}
Step 4: Create Test Runner
// File: [Link]
@RunWith([Link])
@CucumberOptions(
features = "src/test/resources/features",
glue = "[Link]",
plugin = {
"pretty",
"html:target/reports/[Link]",
"json:target/reports/[Link]"
}
)
public class RunCucumberTests {
// Empty class - Cucumber handles everything
}
Step 5: Run Tests
# Run all features
mvn test -Dtest=RunCucumberTests
# Run specific feature
mvn test -Dtest=RunCucumberTests
-[Link]="src/test/resources/features/[Link]"
# Run specific scenario
mvn test -Dtest=RunCucumberTests -[Link]="--name 'User successfully
logs in'"
Interview Answer: "Cucumber + Appium: Write features in plain English, create step definitions
that map to page object methods, use TestNG/JUnit runner. Features are readable by non-technical
people, code is maintainable by QAs."
Q28: Cucumber Feature File Examples
Complete Example:
# File: src/test/resources/features/[Link]
Feature: Payment Checkout Flow
As a user
I want to purchase products
So that I can receive them at my doorstep
Background:
Given User is logged in
Scenario: Successful payment checkout
When User searches for "Laptop"
And User adds "Dell Laptop" to cart
And User goes to checkout
And User enters shipping address "123 Main St"
And User selects shipping method "Express"
And User enters card number "4111111111111111"
And User enters expiry date "12/25"
And User enters CVV "123"
And User taps pay button
Then User should see order confirmation
And Order number should be displayed
Scenario: Payment fails with invalid card
When User goes to checkout
And User enters card number "1234567890123456"
And User enters expiry date "12/25"
And User enters CVV "123"
And User taps pay button
Then User should see error "Invalid card number"
And Retry button should be visible
Interview Answer: "Cucumber feature files use Given-When-Then format. Given sets up initial
state, When performs actions, Then verifies results. Background runs before each scenario."
Q29: Cucumber Data Tables
Scenario with Multiple Data:
Feature: Bulk User Creation
Scenario: Create multiple users
When User creates following users:
| Name | Email | Phone |
| Alice | alice@[Link] | 9876543210 |
| Bob | bob@[Link] | 9876543211 |
| Carol | carol@[Link] | 9876543212 |
Then All users should be created successfully
Step Definition with Data Table:
@When("User creates following users:")
public void createMultipleUsers(DataTable dataTable) {
List<Map<String, String>> users = [Link]()
for (Map<String, String> user : users) {
String name = [Link]("Name")
String email = [Link]("Email")
String phone = [Link]("Phone")
[Link](name)
[Link](email)
[Link](phone)
[Link]()
}
}
Interview Answer: "DataTable allows passing multiple rows of data in feature file. Step definition
receives it as List and iterates through rows."
Q30: Cucumber Hooks & Scenarios
Example with Hooks:
// Before and After each scenario
public class Hooks {
private AppiumDriver driver
@Before
public void beforeScenario(Scenario scenario) {
[Link]("Starting scenario: " + [Link]())
driver = [Link]()
}
@After
public void afterScenario(Scenario scenario) {
if ([Link]()) {
[Link]("Scenario FAILED: " + [Link]())
// Take screenshot
[Link]([Link]())
} else {
[Link]("Scenario PASSED: " + [Link]())
}
// Cleanup
[Link]()
}
}
Interview Answer: "@Before hook runs before each scenario (setup). @After runs after each
scenario (teardown). @BeforeAll/@AfterAll run once for all scenarios."
🚀 SECTION 7: ADVANCED REAL-TIME SCENARIOS
Q31: Element Hidden Behind Keyboard
Problem:
User wants to tap login button
But keyboard covers it
Element exists but not visible
Solution:
public class LoginPage {
@AndroidFindBy(id = "login_button")
private WebElement loginButton
public HomePage tapLogin() {
// Hide keyboard first
[Link]()
// Wait for button to be visible
[Link](loginButton, [Link])
// Tap it
[Link]()
return new HomePage()
}
}
Interview Answer: "When element is hidden behind keyboard, call [Link]() before
tapping. Alternative: tap an element that auto-hides keyboard like pressing Enter."
Q32: App Crashes During Test
Problem:
Test running fine
Suddenly: "Session was terminated"
App crashed
Solution in TestListener:
public class TestListener implements ITestListener {
@Override
public void onTestFailure(ITestResult result) {
Throwable throwable = [Link]()
// Check if app crashed
if (throwable instanceof SessionNotCreatedException) {
[Link]("App crashed, attempting recovery")
// Get app package
String appPackage = [Link]()
// Kill app
[Link]().exec("adb shell am force-stop " + appPackage)
// Wait 2 seconds
[Link](2000)
// Relaunch app
[Link](appPackage)
[Link]("App relaunched successfully")
}
}
}
Interview Answer: "Check for SessionNotCreated exception in TestListener. If app crashed, force-
stop it, wait, and relaunch. Log crash details for debugging."
Q33: Dynamic Element IDs (Changes Every Time)
Problem:
Element ID: element_123456 (first time)
Element ID: element_789012 (second time)
Hard to locate when ID changes
Solution:
public class DynamicElementPage {
// BAD: ID is hardcoded, won't work next time
// @AndroidFindBy(id = "element_123456")
// GOOD: Use partial ID match
@AndroidFindBy(xpath = "//[Link][contains(@resource-id,
'element_')]")
private WebElement dynamicButton
// OR: Use text if available
@AndroidFindBy(xpath = "//[Link][@text='Search']")
private WebElement searchButton
// OR: Use content-desc if available
@AndroidFindBy(accessibility = "Search Button")
private WebElement searchByAccessibility
// OR: Use class and index
@AndroidFindBy(xpath = "(//[Link])[1]")
private WebElement firstButton
}
Interview Answer: "For dynamic IDs use XPath with contains() for partial matching, or use
content-desc, text, or class-based XPath. Never hardcode dynamic IDs."
Q34: Modal Popup Randomly Appearing
Problem:
Sometimes popup appears: "Rate our app?"
Sometimes it doesn't
Blocks test randomly
Solution:
public void dismissRandomPopupIfExists() {
try {
// Try to find popup with SHORT timeout
WebDriverWait wait = new WebDriverWait(driver,
[Link](2))
[Link]([Link](
[Link]("//[Link][@text='Cancel']")))
// If found, dismiss it
[Link]([Link](
"//[Link][@text='Cancel']")).click()
[Link]("Dismissed popup")
} catch (TimeoutException e) {
// No popup, continue
[Link]("No popup present, continuing")
}
}
// Call this in @BeforeMethod or before important steps
@BeforeMethod
public void setup() {
dismissRandomPopupIfExists()
// Continue with test
}
Interview Answer: "For random popups use try-catch with short timeout. If popup found, dismiss
it. If not found (timeout), continue. Never fail test just because popup didn't appear."
Q35: Element Exists But Click Doesn't Work
Problem:
Element visible in screenshot
tap(element) executes
No action happens
Why??
Debugging:
public void debugClickIssue(WebElement element) {
// Check 1: Is it enabled?
boolean isEnabled = [Link]()
[Link]("Is enabled: " + isEnabled)
// Check 2: Is it displayed?
boolean isDisplayed = [Link]()
[Link]("Is displayed: " + isDisplayed)
// Check 3: What's its location?
Point location = [Link]()
[Link]("Element at: " + location.x + ", " + location.y)
// Check 4: What's its size?
Dimension size = [Link]()
[Link]("Element size: " + [Link] + ", " + [Link])
// Check 5: Scroll to make sure it's fully visible
[Link]("mobile: scroll", [Link](
"direction", "down"))
// Check 6: Try different click approaches
// Approach 1: Direct click
try {
[Link]()
[Link]("Direct click worked")
return
} catch (Exception e) {
[Link]("Direct click failed: " + [Link]())
}
// Approach 2: Actions class
try {
new Actions(driver)
.moveToElement(element)
.click()
.perform()
[Link]("Actions click worked")
return
} catch (Exception e) {
[Link]("Actions click failed: " + [Link]())
}
// Approach 3: JavaScript
try {
[Link]("arguments[0].click()", element)
[Link]("JavaScript click worked")
return
} catch (Exception e) {
[Link]("JavaScript click failed: " + [Link]())
}
}
Interview Answer: "When tap doesn't work: (1) Verify element is enabled and displayed, (2)
Check its location and size, (3) Scroll it into view, (4) Try different tap approaches like Actions or
JavaScript."
Q36: Test Passes Locally, Fails in Jenkins
Common Causes & Fixes:
CAUSE 1: Slow CI Server
├─ Local: Test passes in 5 seconds
├─ Jenkins: Server slow, element loads in 15 seconds
└─ Fix: Increase timeout for CI environment
[Link]=30 (vs [Link]=10)
CAUSE 2: Different APK Version
├─ Local: Testing APK version 2.5
├─ Jenkins: Testing APK version 2.3
├─ Elements different → Test breaks
└─ Fix: Use same APK version
CAUSE 3: Different Android Version
├─ Local: Emulator with Android 14
├─ Jenkins: Device with Android 13
├─ UI looks different
└─ Fix: Match Android version or test on both
CAUSE 4: Different Device Resolution
├─ Local: 1080x2400
├─ Jenkins: 720x1600
├─ Coordinates break
└─ Fix: Use ID locators, NOT coordinates
CAUSE 5: Parallel Test Conflicts
├─ Locally: Running 1 test
├─ Jenkins: Running 5 tests parallel
└─ ThreadLocal driver conflicts
└─ Fix: Verify ThreadLocal is used correctly
CAUSE 6: Missing Dependencies on Jenkins
├─ Local: Appium server running
├─ Jenkins: Appium not started
└─ Fix: Start Appium in Jenkins pipeline
CAUSE 7: Network Issues
├─ Local: Fast network
├─ Jenkins: Slow network
├─ API calls timeout
└─ Fix: Increase API timeouts for CI
Debugging Approach:
# Step 1: Check CI console output
cat logs/[Link] | grep ERROR
# Step 2: Check Appium logs
cat reports/logs/[Link] | grep error
# Step 3: Check device logs
adb logcat > [Link]
grep CRASH [Link]
# Step 4: Compare local vs CI
- APK versions
- Android versions
- Device resolution
- Appium server running?
- Dependencies installed?
# Step 5: Run single test from CI
mvn test -Dtest=OneTest -Denv=staging
# Step 6: Run with verbose logging
mvn test -X -DfailIfNoTests=false
Interview Answer: "When CI fails differently: Check APK version match, Android version match,
Appium server running, increase timeouts for CI, verify ThreadLocal driver isolation, check
network connectivity, enable verbose logging."
Q37: Screenshots Eating Disk Space
Problem:
1000 tests run
Each failure = 1MB screenshot
After run: 1GB+ screenshots
Jenkins disk full ❌
Solution:
public class ScreenshotUtil {
public static String capture(String testName) {
// Take screenshot
File src = ((TakesScreenshot) driver)
.getScreenshotAs([Link])
// Create filename with timestamp
String filename = testName + "_"
+ [Link]().format(
[Link]("yyyyMMdd_HHmmss"))
+ ".png"
String path = AppConstants.SCREENSHOTS_PATH + filename
File dest = new File(path)
[Link]().mkdirs()
// Copy to destination
[Link](src, dest)
// AUTO-DELETE old screenshots (older than 7 days)
deleteOldScreenshots()
return [Link]()
}
private static void deleteOldScreenshots() {
File screenshotDir = new File(AppConstants.SCREENSHOTS_PATH)
if (![Link]()) return
File[] files = [Link]()
if (files == null) return
long now = [Link]()
long sevenDaysAgo = now - (7 * 24 * 60 * 60 * 1000)
for (File file : files) {
if ([Link]() < sevenDaysAgo) {
[Link]()
[Link]("Deleted old screenshot: " + [Link]())
}
}
}
}
Jenkins Pipeline Configuration:
pipeline {
stages {
stage('Tests') {
steps {
sh 'mvn test'
}
}
}
post {
always {
// Archive screenshots but limit size
archiveArtifacts artifacts: 'reports/screenshots/**',
allowEmptyArchive: true
// Clean old artifacts
sh 'find reports/screenshots -mtime +7 -delete'
}
}
}
Interview Answer: "Implement automatic cleanup of screenshots older than 7 days. Configure
Jenkins post-stage to delete old artifacts. Monitor disk usage and alert when > 80%."
Q38: Flaky Tests - Element Sometimes Exists
Problem:
Test 1: PASS
Test 2: FAIL (same test)
Test 3: PASS
Test 4: FAIL
Same test code, inconsistent results = FLAKY TEST ❌
Common Causes:
CAUSE 1: Timing Issues
├─ Element loads sometimes in 3 sec, sometimes in 10 sec
└─ Fix: Increase wait timeout
CAUSE 2: Network Delays
├─ API response sometimes fast, sometimes slow
└─ Fix: Increase API timeouts
CAUSE 3: App State Issues
├─ Old data from previous test interferes
└─ Fix: Clear app data in @BeforeMethod
CAUSE 4: Device Performance
├─ Device slow sometimes
└─ Fix: Run tests sequentially, not parallel
CAUSE 5: Stale Elements
├─ Element found, screen refreshes, element gone
└─ Fix: Find element fresh before each action
CAUSE 6: Background Processes
├─ Notification arrives, popup appears
└─ Fix: Dismiss popups, disable notifications
Solution - Retry Logic:
public class RetryAnalyzer implements IRetryAnalyzer {
private int attempt = 0
private final int maxRetry = 2
@Override
public boolean retry(ITestResult result) {
if (![Link]() && attempt < maxRetry) {
attempt++
[Link]("Retry {}/{} for {}",
attempt, maxRetry,
[Link]().getMethodName())
return true // Retry this test
}
return false // Don't retry
}
}
// In test class
@Test(retryAnalyzer = [Link])
public void testFlakyElement() {
// If fails, automatically retries 2 times
}
Investigation Checklist:
# 1. Run test 10 times, see if it fails
for i in {1..10}; do mvn test -Dtest=OneTest; done
# 2. Check logs for timing issues
grep -i "timeout\|wait" reports/logs/[Link]
# 3. Check for stale elements
grep -i "stale" reports/logs/[Link]
# 4. Check device logs
adb logcat | grep -i "error\|crash"
# 5. Increase waits and retest
# Modify config: [Link]=10 → [Link]=20
# Run 10 times again
# 6. If still flaky, investigate app behavior
# Is there a timing issue in app itself?
Interview Answer: "For flaky tests I investigate root cause: timing (increase waits), app state (clear
data), stale elements (find fresh), network delays. Implement retry logic as band-aid fix while
investigating."
Q39: Network Throttling & Offline Testing
Simulate Slow Network:
// Simulate network speed
public void throttleNetwork(NetworkSpeed speed) {
switch (speed) {
case SLOW_3G:
// Throttle to 3G speed
[Link]().exec(
"adb shell svc network simulate SLOW_3G")
break
case FAST_4G:
// Throttle to 4G speed
[Link]().exec(
"adb shell svc network simulate FAST_4G")
break
case WIFI:
// Restore full speed
[Link]().exec(
"adb shell svc network simulate WIFI")
break
}
}
// Simulate offline mode
public void goOffline() {
[Link]().exec("adb shell svc wifi disable")
[Link]().exec("adb shell svc data disable")
}
public void goOnline() {
[Link]().exec("adb shell svc wifi enable")
[Link]().exec("adb shell svc data enable")
}
// Test offline behavior
@Test
public void testOfflineErrorHandling() {
// Go offline
goOffline()
// Try to search (should fail gracefully)
[Link]("Laptop")
// Should show offline message
[Link]([Link]())
// Go online
goOnline()
// Retry should work
[Link]()
[Link]([Link]())
}
Interview Answer: "For network testing use ADB commands to throttle network speed. Simulate
offline mode to test graceful failure. Verify app shows appropriate error messages and recovery
options."
Q40: Orientation Changes & Rotation
Problem:
Portrait (normal): Layout A
Landscape (rotated): Layout B
Test must work in both orientations
Elements might be in different locations
Solution:
@Test
public void testOrientationChange() {
HomePage home = new HomePage()
// Device in portrait
[Link]("Laptop")
[Link]([Link]())
// Rotate to landscape
[Link]([Link])
// Wait for UI to adapt
new WebDriverWait(driver, [Link](10))
.until([Link](
[Link]("landscape_results_layout")))
// Verify results still visible in landscape
[Link]([Link]())
// Elements should reposition
[Link]([Link]())
// Rotate back to portrait
[Link]([Link])
// Wait for UI to adapt again
new WebDriverWait(driver, [Link](10))
.until([Link](
[Link]("portrait_results_layout")))
// Verify back to normal
[Link]([Link]())
}
Interview Answer: "Test orientation by rotating device and waiting for UI to adapt. Verify
elements are visible and clickable in both portrait and landscape orientations."
🎤 SECTION 8: FINAL INTERVIEW Q&A
Q41: Why TestNG Over JUnit?
TestNG > JUnit because:
@BeforeSuite/@AfterSuite
└─ JUnit doesn't have this
@BeforeClass/@AfterClass
└─ JUnit has but less flexible
@DataProvider
└─ JUnit doesn't have built-in
Grouping
└─ TestNG supports groups, JUnit doesn't
Parallel Execution
└─ TestNG: Built-in parallel support
└─ JUnit: Need separate plugins
Dependency
└─ TestNG: Test A must pass before B
└─ JUnit: Not supported
XML Control
└─ TestNG: Control via XML
└─ JUnit: Not as flexible
Interview Answer: "TestNG has more features than JUnit: @BeforeSuite, @DataProvider,
grouping, native parallel execution, dependency management, and XML-based test control."
Q42: Maven vs Gradle
MAVEN:
├─ Uses [Link]
├─ XML configuration
├─ Convention over configuration
├─ More verbose
├─ More widely used
GRADLE:
├─ Uses [Link]
├─ Groovy configuration
├─ More flexible
├─ Less verbose
├─ Faster builds
Interview Answer: "Maven uses XML ([Link]), Gradle uses Groovy ([Link]). For
production: Maven is standard. For new projects: Gradle is faster and more flexible. Both support
same dependencies."
Q43: Continuous Integration (Jenkins)
Simple Pipeline:
pipeline {
agent any
stages {
stage('Setup') {
steps {
sh 'appium &' // Start Appium
sh 'sleep 5'
}
}
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Test') {
steps {
sh 'mvn test -Dsuite=testng/[Link]'
}
}
stage('Reports') {
steps {
publishHTML(target: [
reportDir: 'reports/extent',
reportFiles: '*.html',
reportName: 'Extent Report'
])
}
}
}
post {
always {
archiveArtifacts artifacts: 'reports/**'
}
failure {
emailext subject: "Build Failed",
body: "Check console output",
to: "qa@[Link]"
}
}
}
Interview Answer: "Jenkins automates test execution. Push code → Jenkins runs tests → Publishes
reports → Notifies team. Continuous integration catches bugs early."
Q44: Git Workflow
# Daily workflow
git status # Check what changed
git pull # Get latest from team
git checkout -b myfeature # Create branch
git add . # Stage changes
git commit -m "Add login test" # Save locally
git push # Upload to server
(Create Pull Request)
(Code review)
(Merge to main)
Interview Answer: "Daily Git: pull latest, create feature branch, make changes, commit with clear
message, push to server, create PR, get reviewed, merge. Never commit to main directly."
Q45: How Would You Build Framework from Scratch?
Structured Answer:
LAYER 1 - Foundation (Week 1)
├─ Set up Maven project
├─ Add Appium, TestNG, Selenium dependencies
├─ Create base structure (src/main, src/test)
└─ Set up Git repository
LAYER 2 - Driver Management (Week 1-2)
├─ Create DriverManager with ThreadLocal
├─ Create DriverFactory for Android/iOS
├─ Load capabilities from JSON
├─ Handle Appium server connection
LAYER 3 - Page Objects (Week 2)
├─ Create BasePage parent class
├─ Create page classes for each screen
├─ Use @AndroidFindBy annotations
├─ Implement fluent interface (method chaining)
LAYER 4 - Utils (Week 2-3)
├─ WaitActions (explicit waits)
├─ ElementActions (click, type, getText)
├─ ScreenshotUtil (capture on failure)
├─ DataReader (JSON test data)
├─ LogUtil (logging)
LAYER 5 - Tests (Week 3-4)
├─ Create @BeforeMethod, @AfterMethod
├─ Write smoke tests
├─ Write sanity tests
├─ Write regression tests
├─ Use @DataProvider for test data
LAYER 6 - Reporting (Week 4)
├─ ExtentReports integration
├─ ExtentTestListener for auto-screenshots
├─ Slack/Email notifications
├─ Jenkins artifact archiving
LAYER 7 - CI/CD (Week 4-5)
├─ Create Jenkinsfile
├─ Docker containerization
├─ Cloud device farm setup
├─ Parallel execution config
LAYER 8 - Documentation (Week 5)
├─ README with setup instructions
├─ Code examples
├─ Troubleshooting guide
├─ Best practices document
Interview Answer: "Build layered: driver management → page objects → utilities → tests →
reporting → CI/CD. Test at each layer. Document everything. Start simple, add complexity
gradually. Get team feedback early."
Q46: How to Maintain Framework as It Grows?
Regular Maintenance:
MONTHLY:
├─ Review test failures (see if pattern)
├─ Update flaky test timeout values
├─ Upgrade dependencies (appium, testng)
├─ Delete old reports (save disk space)
QUARTERLY:
├─ Refactor duplicate code
├─ Update page objects based on UI changes
├─ Review and optimize waits
├─ Team training on best practices
ANNUALLY:
├─ Major framework overhaul
├─ Evaluate new tools (new Appium version?)
├─ Performance optimization
├─ Architecture review
├─ ROI calculation
Interview Answer: "Maintain by regular reviews (monthly), refactoring duplicate code, updating
dependencies, monitoring test health, team training, and annual architecture reviews."
Q47: Appium Best Practices - Summary
✅ DO:
├─ Use explicit waits (never [Link])
├─ Follow Page Object Model strictly
├─ Keep locators in page classes only
├─ Use @AndroidFindBy annotations
├─ Use ThreadLocal for driver
├─ Log everything important
├─ Take screenshots on failure
├─ Use TestNG groups for test organization
├─ Data-drive tests with @DataProvider
├─ Document your framework
❌ DON'T:
├─ Use hardcoded coordinates
├─ Put locators in test files
├─ Use [Link] for timing
├─ Ignore flaky tests
├─ Test without assertions
├─ Hardcode test data
├─ Skip logging
├─ Run tests without CI/CD
├─ Ignore code reviews
├─ Leave tests broken
Interview Answer: "Appium best practices: explicit waits (not [Link]), POM (separate
locators from tests), ThreadLocal (parallel execution), TestNG groups (organize tests),
@DataProvider (test data), logging (troubleshooting), CI/CD (automation), code reviews (quality)."
Q48: Biggest Challenges & How You Solved Them
Example Answer:
Challenge 1: Flaky Tests
└─ Problem: Same test passed 3 times, failed 1 time
└─ Root Cause: Element loading time varied 3-15 seconds
└─ Solution: Increased default timeout from 10 to 20 seconds
└─ Result: 100% stable tests now
Challenge 2: Test Execution Time
└─ Problem: 1000 tests took 5 hours to run
└─ Root Cause: Tests running sequentially
└─ Solution: Implemented parallel execution with ThreadLocal
└─ Reduced to 30 minutes (10x faster!)
└─ Result: Faster feedback loop, more releases per day
Challenge 3: Maintenance Burden
└─ Problem: Locators broke when UI changed, broke 50 tests
└─ Root Cause: No centralized locator management
└─ Solution: Implemented strict Page Object Model
└─ Now change in 1 file fixes 50 tests
└─ Result: Reduced maintenance time by 40%
Challenge 4: Element Not Clickable
└─ Problem: Test found element but couldn't click
└─ Root Cause: Keyboard was covering element
└─ Solution: Added hideKeyboard() before all taps
└─ Result: No more "element not interactable" errors
Challenge 5: Framework Growing Too Large
└─ Problem: 10,000 lines in one class
└─ Root Cause: No separation of concerns
└─ Solution: Refactored into: Actions, Utils, Listeners, Reports
└─ Result: Code is maintainable, understandable
Interview Answer: "Biggest challenge was flaky tests due to varying load times. Fixed by profiling
actual load times and adjusting timeouts accordingly. Second challenge was slow execution - solved
with parallel testing. Third was locator changes breaking tests - solved with strict POM."
Q49: Questions to Ask Interviewer
1. "What's your current framework architecture?"
└─ Understand what you're walking into
2. "What are the biggest pain points with current automation?"
└─ Show you can solve their problems
3. "How do you handle test data?"
└─ Show you've thought about scalability
4. "What's your team structure and who supports framework?"
└─ Understand support system
5. "What's your CI/CD pipeline?"
└─ Show you understand DevOps
6. "How do you measure test effectiveness?"
└─ Show you care about metrics
7. "What devices do you test on?"
└─ Show you think about real devices
8. "What's your test flakiness percentage?"
└─ Show you'll improve it
9. "How often do you release to production?"
└─ Understand release frequency
10. "What skills does team currently lack?"
└─ Show you can fill gaps
Q50: Follow-Up Email After Interview
Subject: Thanks for the Appium QA Interview Opportunity
Dear [Interviewer Name],
Thank you for the opportunity to discuss the Automation QA role
on your team. I enjoyed learning about your current framework
architecture and testing challenges.
A few thoughts from our conversation:
1. You mentioned test flakiness being 12% - I reduced flakiness
from 15% to 2% in my current role by implementing proper
explicit waits and retry mechanisms.
2. Your concern about test execution time - I implemented
ThreadLocal-based parallel execution reducing time from
2 hours to 30 minutes.
3. Maintenance challenges with growing test suite - I've found
that strict POM enforcement and organized test structure
significantly improves maintainability.
I'm confident I can bring these improvements to your team and
help you build a world-class automation framework.
Looking forward to hearing from you!
Best regards,
[Your Name]
[Your Phone]
[Your LinkedIn]
📋 FINAL INTERVIEW CHECKLIST
DAY BEFORE INTERVIEW
• ☐ Review this entire document
• ☐ Practice 3 mock scenarios out loud
• ☐ Check your framework on GitHub
• ☐ Prepare 2-3 specific examples with numbers
• ☐ Test camera/microphone for video call
• ☐ Set alarm 1 hour before interview
• ☐ Get 8 hours sleep
DAY OF INTERVIEW
• ☐ Dress professionally
• ☐ Join call 2 minutes early
• ☐ Have this guide on second screen (not visible)
• ☐ Have notepad for questions
• ☐ Smile and make eye contact with camera
• ☐ Speak clearly and slowly
• ☐ Use hand gestures (visible on video)
DURING INTERVIEW
• ☐ Listen completely before answering
• ☐ Pause 2 seconds before speaking (shows thought)
• ☐ Give specific examples with numbers
• ☐ Use golden sentences naturally
• ☐ Ask clarification if unsure
• ☐ Never say "I don't know" └─ Say: "I haven't faced that, but here's how I'd approach it"
• ☐ Take notes on whiteboard (if screen sharing)
IF YOU DON'T KNOW ANSWER
Say: "That's a great question. I haven't personally done that, but here's how I would logically
approach it..."
Then explain your thinking process. Interviewers value problem-solving approach over perfect
knowledge.
🎉 YOU ARE NOW 100% INTERVIEW READY!
This guide covers: ✅ All foundation concepts ✅ 50+ Interview questions with answers ✅ Real-time
scenarios (40+ detailed) ✅ BDD with Cucumber ✅ Payment & OTP flows ✅ Mobile automation
best practices ✅ Framework design ✅ Troubleshooting guide ✅ Interview tips and confidence
boosters
TOTAL CONTENT:
• 50+ Q&A with baby-friendly explanations
• 40+ Real-world scenarios with solutions
• Complete code examples
• Framework architecture guide
• Interview scripts and templates
• Git & Maven commands
• Troubleshooting checklist
Remember:
Interviewer wants someone who: ✓ Understands concepts DEEPLY (not just memorized) ✓ Can
solve REAL problems (not theoretical) ✓ Maintains CODE QUALITY (not quick hacks) ✓
Works WELL WITH TEAM (communication) ✓ Is EAGER TO LEARN (not arrogant)
You have ALL of this.
GO ACK THAT INTERVIEW! 🚀💪🔥
Print this document, read daily for 1 week, practice speaking answers out loud, and you'll ace
ANY Appium interview in the world.
Good Luck! 🎯✨