How to Prepare for a QA Engineer Interview: Part 2 — Advanced Topics and Practice

From theory to practice: API testing, automation, SQL, and real cases from interviews


QA Interview

In Part 1, we covered theoretical testing fundamentals. Now let’s move to practice — the skills that truly distinguish junior QA from middle and senior specialists.

In my experience, 80% of candidates fail interviews not on theory, but on practical tasks. They know what regression testing is but can’t write a good test case. They understand testing principles but get lost when asked to test a real function.

This article will fix that. We’ll cover:

  • How to write quality test cases
  • API testing with examples
  • SQL for QA engineers
  • Automation basics
  • 15+ practical tasks from interviews
  • Real cases and how to solve them

📋 Table of Contents

  1. The Art of Writing Test Cases
  2. API Testing: From Basics to Practice
  3. SQL for QA: What You Need to Know
  4. Introduction to Test Automation
  5. 15 Practical Tasks from Interviews
  6. How to Test Popular Features
  7. Working with Tools
  8. Advice from Senior QA

📝 The Art of Writing Test Cases

Anatomy of a Perfect Test Case

Bad Test Case:

ID: TC001
Title: Test login
Steps: Login to system
Expected: User logged in

Why it’s bad?

  • No preconditions
  • Steps not specific
  • No test data
  • Cannot reproduce
  • No result information

Good Test Case:

Test Case ID: TC_LOGIN_001
Title: Verify successful login with valid credentials

Preconditions:
- User is registered with email: test@example.com
- Password: Test@123
- User is on login page
- Browser: Chrome (latest)

Test Steps:
1. Navigate to https://example.com/login
2. Enter email: test@example.com in "Email" field
3. Enter password: Test@123 in "Password" field
4. Click "Login" button

Expected Results:
- User is redirected to dashboard page (URL: /dashboard)
- Welcome message "Hello, Test User" is displayed
- User avatar appears in top-right corner
- Session cookie is created

Actual Results: [To be filled during execution]
Status: [Pass/Fail]
Executed by: [Name]
Execution Date: [Date]

Test Data:
- Valid Email: test@example.com
- Valid Password: Test@123

Environment:
- OS: Windows 11
- Browser: Chrome 120.0
- Test Environment: Staging

Why it’s good? ✅ Can reproduce without additional questions ✅ Clear, measurable results ✅ Complete environment information ✅ Specific test data


Types of Test Cases with Examples

1. Positive Test Cases

Goal: Verify system works with valid data

Example: User Registration

TC_REG_001: Registration with valid data
- Name: John Doe (2-50 characters)
- Email: john.doe@example.com (valid format)
- Password: SecurePass123! (8+ characters, letters, digits, special chars)
- Confirm Password: SecurePass123! (matches)

Expected: 
✅ Registration successful
✅ Confirmation email sent
✅ User redirected to verification page

2. Negative Test Cases

Goal: Verify handling of incorrect data

Example: Registration with invalid data

TC_REG_002: Registration with short password
- Password: 123

Expected: 
❌ Registration FAILED
✅ Message: "Password must contain at least 8 characters"
✅ Password field highlighted in red
✅ User stays on registration page

TC_REG_003: Registration with existing email
- Email: existing@example.com

Expected:
❌ Registration FAILED
✅ Message: "User with this email already exists"

TC_REG_004: Registration with invalid email
- Email: notanemail

Expected:
❌ Registration FAILED
✅ Message: "Enter valid email address"

TC_REG_005: SQL Injection attempt
- Name: Robert'); DROP TABLE users;--

Expected:
❌ Registration FAILED
✅ Special characters escaped
✅ SQL injection blocked

3. Boundary Test Cases

Example: “Age” field (18-65 years)

TC_AGE_001: Age = 17 (min-1)
Expected: ❌ "Minimum age is 18"

TC_AGE_002: Age = 18 (min)
Expected: ✅ Accepted

TC_AGE_003: Age = 19 (min+1)
Expected: ✅ Accepted

TC_AGE_004: Age = 64 (max-1)
Expected: ✅ Accepted

TC_AGE_005: Age = 65 (max)
Expected: ✅ Accepted

TC_AGE_006: Age = 66 (max+1)
Expected: ❌ "Maximum age is 65"

TC_AGE_007: Age = 0
Expected: ❌ "Enter valid age"

TC_AGE_008: Age = -5
Expected: ❌ "Age cannot be negative"

TC_AGE_009: Age = "abc"
Expected: ❌ "Age must be a number"

Practical Interview Assignment

Task: “Write test cases for ‘Forgot Password?’ function”

My Solution:

Positive Scenarios:

TC_FORGOT_001: Reset password with registered email
Preconditions: User with test@example.com is registered
Steps:
1. Click "Forgot Password?"
2. Enter test@example.com
3. Click "Send"
Expected:
- Message: "Email sent to test@example.com"
- Email received within 2 minutes
- Link in email is valid
- Redirect to new password creation page
- New password successfully set

Negative Scenarios:

TC_FORGOT_002: Unregistered email
Steps: Enter notexist@example.com
Expected: 
- Message: "User not found" 
  OR (more secure)
- Message: "If email exists, email will be sent"

TC_FORGOT_003: Empty email field
Expected: "Enter email address"

TC_FORGOT_004: Invalid email format
Input: notanemail
Expected: "Enter valid email"

TC_FORGOT_005: Multiple requests (rate limiting)
Steps: Send 10 requests in 1 minute
Expected: 
- After 5 requests: "Too many attempts. Try again in 15 minutes"
- IP/email blocking

Additional Checks:

TC_FORGOT_006: Link expiration
Steps: Use link after 25 hours (if limit is 24h)
Expected: "Link expired. Request a new one"

TC_FORGOT_007: Using link twice
Steps: 
1. Follow link, change password
2. Try to use the same link again
Expected: "Link already used"

TC_FORGOT_008: SQL Injection in email field
Input: '; DROP TABLE users; --
Expected: Request safely handled

TC_FORGOT_009: XSS attempt
Input: <script>alert('XSS')</script>@test.com
Expected: Special characters escaped

🔌 API Testing: From Basics to Practice

What is API?

API (Application Programming Interface) — interface through which applications communicate with each other.

Real-life analogy: You (client) → Waiter (API) → Kitchen (server)

You don’t go to the kitchen directly. The waiter takes your order (request), passes it to the kitchen, and brings you food (response).

REST API Basics

Main HTTP Methods:

MethodPurposeExample
GETRetrieve dataGet list of users
POSTCreate new resourceCreate new user
PUTUpdate entire resourceUpdate all user data
PATCHUpdate part of resourceUpdate only user email
DELETEDelete resourceDelete user

Response Codes (Status Codes):

2xx — Success:

  • 200 OK: Request successful
  • 201 Created: Resource created
  • 204 No Content: Successful but no data to return

4xx — Client Errors:

  • 400 Bad Request: Invalid request
  • 401 Unauthorized: Not authorized
  • 403 Forbidden: Access denied
  • 404 Not Found: Resource not found
  • 422 Unprocessable Entity: Validation failed

5xx — Server Errors:

  • 500 Internal Server Error: Server error
  • 502 Bad Gateway: Proxy issues
  • 503 Service Unavailable: Service unavailable

Practical API Testing

Scenario: Testing User API

Endpoint: https://api.example.com/users

1. GET Request — Get list of users

Request:

GET /api/users HTTP/1.1
Host: api.example.com
Authorization: Bearer <token>

What we test:

Status Code:

pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
});

Response Time:

pm.test("Response time is less than 500ms", function () {
    pm.expect(pm.response.responseTime).to.be.below(500);
});

Response Structure:

pm.test("Response has correct structure", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property('data');
    pm.expect(jsonData.data).to.be.an('array');
    pm.expect(jsonData.data[0]).to.have.property('id');
    pm.expect(jsonData.data[0]).to.have.property('name');
    pm.expect(jsonData.data[0]).to.have.property('email');
});

Data Types:

pm.test("Data types are correct", function () {
    var user = pm.response.json().data[0];
    pm.expect(user.id).to.be.a('number');
    pm.expect(user.name).to.be.a('string');
    pm.expect(user.email).to.be.a('string');
    pm.expect(user.active).to.be.a('boolean');
});

2. POST Request — Create user

Request:

POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer <token>

{
  "name": "John Doe",
  "email": "john.doe@example.com",
  "password": "SecurePass123!"
}

Test Cases:

// TC_API_001: Create with valid data
pm.test("User created successfully", function () {
    pm.response.to.have.status(201);
    var jsonData = pm.response.json();
    pm.expect(jsonData.message).to.eql("User created successfully");
    pm.expect(jsonData.data.name).to.eql("John Doe");
    pm.expect(jsonData.data.email).to.eql("john.doe@example.com");
    
    // Save ID for subsequent tests
    pm.environment.set("userId", jsonData.data.id);
});

// TC_API_002: Create with existing email
pm.test("Duplicate email returns 422", function () {
    pm.response.to.have.status(422);
    var jsonData = pm.response.json();
    pm.expect(jsonData.error).to.include("email already exists");
});

// TC_API_003: Create without required field
pm.test("Missing required field returns 400", function () {
    pm.response.to.have.status(400);
    var jsonData = pm.response.json();
    pm.expect(jsonData.errors).to.have.property("email");
});

// TC_API_004: Invalid email format
pm.test("Invalid email format returns 422", function () {
    pm.response.to.have.status(422);
    var jsonData = pm.response.json();
    pm.expect(jsonData.errors.email).to.include("valid email");
});

API Security Testing

Important Security Checks:

1. Authentication

// TC_SEC_001: Request without token
pm.test("Request without token returns 401", function () {
    pm.response.to.have.status(401);
});

// TC_SEC_002: Request with invalid token
pm.test("Request with invalid token returns 401", function () {
    pm.response.to.have.status(401);
    var jsonData = pm.response.json();
    pm.expect(jsonData.error).to.include("Invalid token");
});

// TC_SEC_003: Expired token
pm.test("Expired token returns 401", function () {
    pm.response.to.have.status(401);
    var jsonData = pm.response.json();
    pm.expect(jsonData.error).to.include("Token expired");
});

2. Authorization

// TC_SEC_004: Regular user cannot delete another user
pm.test("Non-admin cannot delete user", function () {
    pm.response.to.have.status(403);
});

🗄️ SQL for QA Engineers

Why QA Needs SQL?

  1. Data Validation — verify API correctly saved data in DB
  2. Test Data Preparation — create test records
  3. Logic Verification — ensure business logic correctness
  4. Debugging — understand bug cause
  5. Data Cleanup — clean test data

Basic SQL Commands for QA

1. SELECT — Retrieving Data

Basic SELECT:

-- Get all users
SELECT * FROM users;

-- Get specific columns
SELECT id, name, email FROM users;

-- With condition
SELECT * FROM users WHERE email = 'test@example.com';

-- With sorting
SELECT * FROM users ORDER BY created_at DESC;

-- With limit
SELECT * FROM users LIMIT 10;

Practical Example:

-- Verify user created after API call
SELECT id, name, email, created_at 
FROM users 
WHERE email = 'john.doe@example.com'
AND created_at > NOW() - INTERVAL '5 minutes';

2. WHERE — Filtering

-- Equals
SELECT * FROM users WHERE status = 'active';

-- Not equals
SELECT * FROM users WHERE status != 'deleted';

-- Greater/less than
SELECT * FROM orders WHERE total_amount > 100;

-- LIKE (pattern search)
SELECT * FROM users WHERE email LIKE '%@gmail.com';

-- IN (one of values)
SELECT * FROM orders WHERE status IN ('pending', 'processing');

-- BETWEEN (range)
SELECT * FROM orders WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31';

-- IS NULL / IS NOT NULL
SELECT * FROM users WHERE deleted_at IS NULL;

3. JOIN — Joining Tables

INNER JOIN:

-- Get orders with user information
SELECT 
    orders.id,
    orders.total_amount,
    users.name,
    users.email
FROM orders
INNER JOIN users ON orders.user_id = users.id;

LEFT JOIN:

-- Get all users and their orders (even if no orders)
SELECT 
    users.name,
    COUNT(orders.id) as order_count
FROM users
LEFT JOIN orders ON users.id = orders.user_id
GROUP BY users.id, users.name;

Practical Case:

-- Find users without orders (potential issue?)
SELECT users.id, users.name, users.email
FROM users
LEFT JOIN orders ON users.id = orders.user_id
WHERE orders.id IS NULL;

4. GROUP BY and Aggregate Functions

-- COUNT - counting
SELECT status, COUNT(*) as count
FROM orders
GROUP BY status;

-- SUM - sum
SELECT user_id, SUM(total_amount) as total_spent
FROM orders
GROUP BY user_id;

-- AVG - average
SELECT AVG(total_amount) as average_order_value
FROM orders;

-- MIN and MAX
SELECT 
    MIN(total_amount) as smallest_order,
    MAX(total_amount) as largest_order
FROM orders;

Practical SQL Queries for Testing

Scenario 1: Validation After Transaction

Task: After API call creating order, verify:

  1. Order created in DB
  2. User balance decreased
  3. Status correct
-- 1. Verify order created
SELECT * FROM orders 
WHERE user_id = 123 
AND created_at > NOW() - INTERVAL '1 minute'
ORDER BY created_at DESC 
LIMIT 1;

-- 2. Verify balance changed
SELECT 
    u.id,
    u.balance as current_balance,
    (SELECT balance FROM user_balance_history 
     WHERE user_id = u.id 
     ORDER BY created_at DESC 
     LIMIT 1 OFFSET 1) as previous_balance,
    u.balance - (SELECT balance FROM user_balance_history 
                  WHERE user_id = u.id 
                  ORDER BY created_at DESC 
                  LIMIT 1 OFFSET 1) as balance_change
FROM users u
WHERE u.id = 123;

-- 3. Verify status
SELECT status FROM orders WHERE id = 456;
-- Expected: 'pending' or 'paid'

Scenario 2: Data Integrity Check

-- Find orphaned orders (orders without user)
SELECT orders.*
FROM orders
LEFT JOIN users ON orders.user_id = users.id
WHERE users.id IS NULL;

-- Find users with negative balance
SELECT id, name, balance
FROM users
WHERE balance < 0;

-- Check for duplicate emails
SELECT email, COUNT(*) as count
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

Scenario 3: Business Logic Check

-- Verify order total = items sum + shipping
SELECT 
    o.id,
    o.total_amount,
    SUM(oi.price * oi.quantity) as items_total,
    o.shipping_cost,
    SUM(oi.price * oi.quantity) + o.shipping_cost as calculated_total,
    o.total_amount - (SUM(oi.price * oi.quantity) + o.shipping_cost) as difference
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
GROUP BY o.id
HAVING ABS(o.total_amount - (SUM(oi.price * oi.quantity) + o.shipping_cost)) > 0.01;
-- If difference != 0, there's a calculation error!

🤖 Introduction to Test Automation

When Do You Need Automation?

Automate if: ✅ Tests repeat regularly (regression) ✅ Test takes long time manually ✅ Need to test on multiple configurations ✅ High risk of human error ✅ ROI justified (automation will pay off)

DON’T automate if: ❌ Test executes rarely ❌ UI changes frequently ❌ Visual assessment required ❌ Exploratory testing ❌ Usability testing


Automation Pyramid

        /\
       /  \        E2E Tests (10%)
      /    \       - Slow
     /  UI  \      - Brittle
    /--------\     - Expensive
   /          \    
  / Integration\   Integration Tests (30%)
 /    Tests     \  - Medium speed
/______________\  - API, services
\              /
 \            /   Unit Tests (60%)
  \   Unit   /    - Fast
   \ Tests  /     - Reliable
    \      /      - Cheap
     \    /
      \  /
       \/

Ideal Distribution:

  • 60% — Unit tests (developers)
  • 30% — Integration/API tests (QA + Dev)
  • 10% — E2E UI tests (QA)

💼 15 Practical Tasks from Interviews

Task 1: Testing Search Field

Question: “How would you test the search field on Amazon?”

Answer:

Functional Testing:

  1. Search with valid query
  2. Search with partial match
  3. Search with typos (autocorrect?)
  4. Search with empty query
  5. Search with special characters
  6. Search with very long text (1000+ characters)
  7. Search in different languages
  8. Case sensitivity
  9. Filters and sorting results
  10. Results pagination

Non-Functional: 11. Performance: response time < 2 sec 12. Search 1000 products simultaneously 13. Autocomplete (suggestions) 14. Search history 15. Caching

Security: 16. SQL Injection: ' OR '1'='1 17. XSS: <script>alert('xss')</script>

Usability: 18. Clear search button 19. Highlight search query in results 20. “No results found” — useful suggestions


Task 2: Testing a Button

Question: “How would you test a ‘Submit’ button?”

Answer:

Visual:

  1. Button displays correctly
  2. Correct text
  3. Correct color and style
  4. Correct size
  5. Hover effect works
  6. Disabled state displays

Functional: 7. Mouse click works 8. Keyboard Enter works 9. Touch on mobile works 10. Performs correct action 11. Disabled button not clickable 12. Loading state during processing

Accessibility: 13. Tab navigation available 14. Screen reader reads button 15. ARIA attributes present

Performance: 16. Double-click prevention 17. Debouncing when necessary

Cross-browser: 18. Chrome, Firefox, Safari, Edge 19. Mobile browsers


Task 3: Testing Shopping Cart

Question: “Design tests for shopping cart”

Answer:

Adding Items:

  1. Add 1 item
  2. Add multiple items
  3. Add same item twice (quantity increases)
  4. Add out of stock item
  5. Add more than available in stock
  6. Add item with discount
  7. Add item with variations (size, color)

Updating Quantity: 8. Increase quantity 9. Decrease quantity 10. Set quantity = 0 (item removed?) 11. Enter negative number 12. Enter non-numeric value 13. Exceed available quantity

Removal: 14. Remove one item 15. Remove all items 16. Clear cart

Calculations: 17. Subtotal correct 18. Apply promo code 19. Tax calculation 20. Shipping calculation 21. Total = subtotal + tax + shipping - discount

Persistence: 22. Cart saves after logout/login 23. Cart syncs between devices 24. Cart saved in cookies/localStorage

Edge Cases: 25. Maximum items in cart 26. Item removed from catalog (but in cart) 27. Item price changed 28. Stock quantity decreased


Task 4: Testing Login/Logout Flow

Test Cases:

Login - Positive:

  1. Valid email + password
  2. “Remember me” works
  3. Redirect to intended page after login

Login - Negative: 4. Wrong password → error 5. Non-existent email → error 6. Empty fields → error 7. SQL injection attempt 8. After 5 failed attempts → lockout 9. Expired session → requires re-login

Logout: 10. Logout clears session 11. Back button after logout → requires login 12. Tokens invalidated 13. “Logout from all devices” works


Task 5: Testing Payment Form

Critical Checks:

Card Data:

  1. Valid card number (Luhn algorithm)
  2. Invalid card number
  3. Expired card
  4. Wrong CVV
  5. Test cards work (staging)

Security: 6. Card number masked (**** **** **** 1234) 7. CVV not saved 8. HTTPS connection 9. PCI DSS compliance

Payment Process: 10. Successful payment 11. Declined payment 12. Timeout 13. Insufficient funds 14. 3D Secure verification

Integration: 15. Webhook received 16. Confirmation email sent 17. Order updated in DB 18. Invoice generated


Testing Calculator

Basic Operations:

+ : Addition
- : Subtraction
× : Multiplication
÷ : Division

Test Cases:

Positive:

  1. 2 + 2 = 4
  2. 10 - 5 = 5
  3. 3 × 4 = 12
  4. 20 ÷ 4 = 5
  5. 0 + 5 = 5
  6. 10 - 0 = 10
  7. Negative numbers: -5 + 3 = -2
  8. Decimal numbers: 1.5 + 2.5 = 4
  9. Large numbers: 999999 + 1 = 1000000

Boundary: 10. Division by zero → Error 11. Maximum number 12. Minimum number 13. Many decimal places

Order of Operations: 14. 2 + 3 × 4 = 14 (not 20) 15. (2 + 3) × 4 = 20 16. Nested parentheses

UI: 17. CE (Clear Entry) vs C (Clear All) 18. Backspace deletes last digit 19. Comma vs period (localization)


🛠️ Working with Tools

JIRA Best Practices

Well-Written Bug:

Summary: 
[Login] Unable to login with valid credentials on Chrome

Environment:
OS: Windows 11
Browser: Chrome 120.0.6099
URL: https://staging.example.com/login
Account: test@example.com

Steps to Reproduce:
1. Navigate to https://staging.example.com/login
2. Enter email: test@example.com
3. Enter password: Test@123
4. Click "Login" button

Expected Result:
- User is logged in
- Redirected to /dashboard

Actual Result:
- Login button shows loading spinner indefinitely
- No error message displayed
- User remains on login page

Additional Information:
- Console error: "TypeError: Cannot read property 'token' of undefined"
- Network tab shows 500 Internal Server Error for POST /api/auth/login
- Issue reproducible 100% of the time
- Works fine on Firefox and Safari

Attachments:
- screenshot.png
- console_log.txt
- network_har_file.har

Severity: High
Priority: High
Affected Version: 2.1.0

💡 Advice from Senior QA

1. Think Like a User

Don’t just follow test cases. Ask yourself:

  • How will a real user use this?
  • What unexpected actions might they take?
  • What could go wrong?

2. Document Everything

  • Clear reproduction steps
  • Screenshots/video
  • Logs
  • Environment details

Bad: “Bug in login” Good: [Example above in JIRA section]

3. Automate Smartly

Don’t automate everything. Start with:

  • Smoke tests
  • Regression for stable features
  • API tests (high ROI)

4. Communication is Key

  • Clearly explain bugs
  • Be proactive
  • Participate in planning
  • Share feedback

5. Never Stop Learning

  • New tools
  • New methodologies
  • New technologies

🎓 Final Checklist Before Interview

✅ Practice:

  • Wrote 50+ test cases
  • Found real bugs on demo sites
  • Practiced API testing in Postman
  • Wrote 10+ SQL queries
  • Created simple automation script
  • Solved all 15 practical tasks

✅ Theory:

  • Can explain everything from Part 1
  • Understand difference between all testing types
  • Know when to use each test design technique
  • Confidently explain API testing
  • Understand SQL basics

✅ Soft Skills:

  • Prepared 5+ STAR stories
  • Ready to explain testing approach
  • Can talk about past projects
  • Prepared questions for interviewer

🚀 Conclusion

Preparing for QA interview isn’t just memorization. It’s developing QA mindset:

  • Critical thinking
  • Attention to detail
  • Analytical skills
  • Communication

Remember three main tips:

  1. Practice > Theory — write test cases, find bugs, test real applications

  2. Understanding > Memorization — important not to memorize definitions but understand concepts

  3. Curiosity > Knowledge — show in interview that you love learning and growing


Good luck on your interview! 🍀

If this article helped you, give it a 👏 and share with friends!

Have questions? Write in comments — I’ll answer all!