// Interview Prep/Prep plans/21-Day SDET Prep Plan
ποΈ 21-Day SDET Prep Plan
Mid-to-senior engineers preparing for SDET roles where the bar includes live coding, framework architecture discussions, and CI/CD system design. Assumes you can write code already β this plan sharpens your coding craft, builds an interview-ready framework artefact, and targets the deep technical question banks SDET interviews use.
// GOAL
Arrive at the SDET interview with production-quality test framework code on GitHub, a working CI pipeline, and confident answers to questions on OOP, framework architecture, API automation, SQL, and test infrastructure design.
// THE PLAN
Sharpen the OOP principles and coding habits SDET interviewers test before any framework work begins
// STUDY
- Data structures in practice: arrays, linked lists, hash maps, and sets β how to traverse, search, and transform collections with clean, readable code at the level a live coding screen expects
- OOP principles applied to test code: encapsulation (private locators inside page objects), inheritance (shared base class), polymorphism (typed interfaces for interchangeable actions) β understanding when each genuinely helps versus when it over-engineers
- Clean code habits: meaningful naming, single-responsibility methods, no magic strings or magic numbers, methods small enough to be understood at a glance β interviewers grade code quality, not just correctness
- Language fluency: Java generics and collections API, or TypeScript interfaces, generics, and built-in array methods β choose your primary interview language and practise until the syntax is invisible so you can focus on design during the screen
// PRACTISE
- Write a small Java or TypeScript class that wraps a list of test results and exposes typed methods: filterByStatus(status), countByType(type), and getSlowest() β review every name and method for single responsibility before committing
- Given a BasePage class with a protected driver field and a waitForElement(locator, timeout) method, implement a derived LoginPage class with typed login(email, password) and getErrorMessage() methods β use inheritance correctly, not via copy-paste between classes
- Solve 2 short algorithm problems from a practice platform (HackerRank or Codewars) at the level SDET screens use: string manipulation and collection filtering β after a working solution, review it for naming, readability, and any hidden coupling
Deliverable
A LoginPage class with typed methods and 2 solved algorithm problems committed to a public GitHub repository β the codebase you will extend across the full 21 days.
Design and build a structured, maintainable test framework layer by layer
// STUDY
- Page Object Model: separating locators, actions, and assertions β and the common POM anti-patterns interviewers probe for: leaking raw selectors into tests, performing assertions inside page objects, and creating god-class pages that own too many responsibilities
- Test fixture patterns: per-test vs shared fixtures, Builder pattern for typed test data objects, factory methods for creating varied but consistent inputs β the difference between fixtures that make tests readable and fixtures that introduce hidden dependencies
- Design patterns for test code: Builder (test data construction), Factory Method (driver or client instantiation), Singleton (shared configuration), Strategy (interchangeable transport layers) β when each simplifies the framework and when it adds complexity without benefit
- Configuration management: externalising base URL, credentials, timeouts, and environment selection so the same suite runs locally and in CI without code changes β the simplest configuration wins
// PRACTISE
- Refactor your Days 1β4 page objects into a proper framework structure: a config module for environment variables, a base driver or client helper, at least 2 page objects, and a test file that imports only from page objects and never touches a raw selector directly
- Write a Builder class that constructs a typed User test data object with a fluent API: User.builder().withEmail(...).withRole(...).build() β use it to generate 3 distinct test data variants in a parameterised test
- Review your framework against 3 questions from the framework-design question bank β identify any structural weaknesses, refactor the most significant one, and write a one-paragraph justification of the change
Deliverable
A framework with config module, base class, at least 2 page objects, a Builder-pattern test data class, and at least 2 parameterised tests β all passing and committed to GitHub.
Add coded API tests and learn to validate database state as part of a test flow
// STUDY
- REST API testing in code: HTTP client setup (REST Assured given/when/then DSL, or axios/supertest), request construction with headers and path params, status code and body assertion, JSON schema validation, and extracting response values into typed variables for use in subsequent steps
- Chaining API calls across test steps: using the ID or token returned from a POST as the path parameter in a subsequent GET or DELETE β building a createβreadβdelete flow without hard-coded resource IDs that break between test runs
- SQL for test validation: SELECT with WHERE and JOIN for reading database state after a write operation, GROUP BY with COUNT for auditing record counts, and the judgement call of when a database-level assertion adds value over an API check alone
- Test data strategy: idempotent setup that does not fail if the target data already exists, teardown that cleans up exactly what the test created without cascading into unrelated records, and the difference between using a pre-seeded fixture and creating data dynamically per test
// PRACTISE
- Write 3 chained API tests against a public REST API (e.g. reqres.in or jsonplaceholder.typicode.com): POST create with schema assertion on the response body, GET using the returned ID, DELETE and verify 404 on a subsequent GET β the resource ID must flow from step to step, not be hard-coded
- Write 2 SQL queries that mirror what an SDET uses for test validation: one that selects test users created in the last 24 hours from a users table, one that counts test run results grouped by status from a test_runs table β these become your template for database assertions
- Add a test data fixture to your framework that creates a test user via API before the test and deletes it via API in teardown β verify no residual test data persists between runs by running the suite twice consecutively
Deliverable
At least 3 chained API tests and a test data fixture that creates and tears down state automatically β committed alongside the framework from Days 5β9.
Build a complete CI pipeline and practise the system-design round with a written exercise
// STUDY
- GitHub Actions for SDET workflows: trigger on push and pull request, install dependencies, run test shards in parallel jobs, upload an Allure or HTML report as a downloadable artifact, fail the build on any test failure or below a pass-rate threshold
- Parallel execution and sharding: running Playwright test shards or TestNG/JUnit parallel threads β how sharding cuts wall-clock time and the test isolation requirements it enforces (no shared mutable state, no inter-test dependencies on creation order)
- System design for test infrastructure: the 'design a test framework for a microservices platform' question β layer separation (test layer, page/client layer, data layer, config), how tests share infrastructure without coupling, and how the framework evolves from 1 QA to 10
- Flaky test detection and quarantine: tagging unstable tests, running them in isolation with retry, tracking flakiness rate over sprints, and the escalation path that leads to fixing or deleting a test rather than permanent quarantine
// PRACTISE
- Set up a GitHub Actions workflow: install dependencies, run your suite in parallel across at least 2 workers or shards, upload the HTML report as an artifact, and fail the build if any test fails β trigger a deliberate failure and fix it from the Actions log alone without running locally
- Write a 1-page system-design document for: 'Design a test framework for a platform with 5 REST microservices and a React front end β usable by 3 QA engineers and maintainable over 2 years.' Include a layer diagram, dependency strategy, and 2 key trade-offs you made and why
- Add retry logic to one flaky test in your suite: configure the runner to retry up to 2 times before marking it failed, verify the retry count appears in the HTML report, and write a one-paragraph quarantine policy for when a test has failed intermittently for 3 consecutive sprints
Deliverable
A green GitHub Actions pipeline running your suite in parallel with an HTML report artifact, plus a 1-page system-design document for the 5-microservice scenario.
Consolidate every gap, work through the question banks, and simulate both interview rounds under pressure
// STUDY
- Framework-design bank: questions on POM anti-patterns, fixture strategies, design patterns, parallel execution isolation, and test observability β the questions that separate SDET candidates from automation QA candidates
- Core Java or JavaScript/TypeScript bank: data structures, generics, collections API, OOP edge cases β review any question where your answer was a definition rather than a concrete code example
- CI/CD bank: pipeline trigger strategies, sharding and matrix builds, caching layers, artifact management, and failure triage β increasingly tested at senior level as infrastructure ownership becomes part of the SDET scope
- Behavioural and engineering culture: advocating for test quality in a team that treats test code as second-class, onboarding an engineer onto a framework you own, handling a broken pipeline the week before a release β practise structured STAR answers
// PRACTISE
- Answer 10 questions aloud from the framework-design, core Java, and CI/CD banks β time yourself at 90 seconds per answer and flag every question where you stalled or gave a definition instead of a demonstration
- Identify your 5 weakest answers and write a worked example for each, drawing directly on the codebase and pipeline you built across Days 1β17
- Run a 30-minute mock: a colleague gives you a live-coding exercise (extend your framework with a new page object and a parameterised test), followed by a 10-minute walkthrough of your system-design document where they challenge 2 of your decisions
Deliverable
Written answers to your 5 weakest questions plus a mock debrief: what the interviewer challenged, how you responded, and what you would strengthen in your code and system-design document.
Capstone: simulate the technical interview task
Mock task
Set a 60-minute timer. Part 1 β live coding (35 minutes): you receive a skeleton framework with an empty BasePage class, an empty LoginPage class, and a failing test. Extend the framework: add a waitForElement(locator, timeout) method to BasePage that polls every 500 ms and throws a clear error on timeout; implement LoginPage.login(email, password) and LoginPage.getErrorMessage() using that method; write a Builder class for a User test data object with at minimum email, password, and role fields; add a parameterised test that calls login() with 3 User variants from the builder β asserting the success state for valid credentials and the correct error message for invalid ones. Use stable locators and meaningful names throughout. Commit the result. Part 2 β system design (20 minutes): on paper, produce a layer diagram for a test framework that supports both UI (Selenium) and API (REST Assured) tests, is used by 3 engineers in parallel without shared mutable state, and runs in a GitHub Actions pipeline with separate UI and API jobs. Write 2 sentences on the biggest trade-off in your design and what you would change if the team grew to 10 engineers. Part 3 (5 minutes): write a self-review β one thing you would refactor in your code given more time, and one architectural decision in your diagram you are least confident in and what you would research to resolve it.