SoftwareTestPilot
8 Q&A · 3 Years Experience

Python SDET Interview Questions for 3 Years Experience (2026)

Python 3.12 & PyTest automation interview questions for Python Automation Engineers with 3 years of experience.

  • 3 min read
  • Difficulty: Medium
  • 3 yr · Python Automation
  • Updated October 2026
  • SoftwareTestPilot
SoftwareTestPilot
QA Editorial Team
Published:
0 / 8 reviewed
0%

1. pytest Essentials

Medium Very Common 1 minQ1 / 8

Q1.How do pytest fixtures work, and what does yield do inside one?

Detailed explanation

Short answer: a fixture is a function that prepares something a test needs; tests ask for it by naming it as a parameter. Code before yield is setup, code after it is teardown, and teardown runs even if the test fails.

import pytest
import requests

@pytest.fixture(scope="session")
def api():
    session = requests.Session()
    session.headers["Accept"] = "application/json"
    yield session
    session.close()          # teardown

def test_health(api):
    r = api.get("https://httpbin.org/status/200", timeout=10)
    assert r.status_code == 200

Scopes are function (default), class, module, package and session. Put shared fixtures in conftest.py; pytest finds them without imports.

Common mistakes
  • Using session scope for data that tests modify - one test then breaks another
Follow-up questions
  • How does a fixture use another fixture?
  • What does autouse=True do?
RelatedQ3
Easy Very Common 1 minQ2 / 8

Q2.How do you run one test with many inputs using parametrize?

Detailed explanation

Short answer: @pytest.mark.parametrize runs the test once per row. Add ids so the report says which case failed.

import pytest

@pytest.mark.parametrize(
    "email, valid",
    [("qa@example.com", True), ("qa@", False), ("", False)],
    ids=["normal", "missing-domain", "empty"],
)
def test_email_validation(email, valid):
    assert is_valid_email(email) is valid

Expected report lines look like test_email_validation[missing-domain] PASSED.

Follow-up questions
  • How do you mark one parameter row as expected to fail? (pytest.param(..., marks=pytest.mark.xfail))
Easy Very Common 1 minQ3 / 8

Q3.How do you group and select tests with markers?

Detailed explanation

Short answer: tag tests with @pytest.mark.smoke, register the marker in config, then select with -m.

# pytest.ini
[pytest]
markers =
    smoke: fast checks run on every commit
    slow: long-running tests
addopts = --strict-markers
pytest -m "smoke and not slow"
pytest -k "login"   # select by name instead

--strict-markers turns a typo like @pytest.mark.smok into an error instead of a silently skipped selection.

Medium Common 1 minQ4 / 8

Q4.How do you share a fixture across files, and where does conftest.py apply?

Detailed explanation

Short answer: a fixture in conftest.py is available to every test in that folder and its subfolders. You can have a root conftest for shared setup and folder-level ones for, say, tests/api/ only.

Use pytest --fixtures to list available fixtures and where they come from - useful when a name is defined twice and you are not sure which one wins (the closest conftest wins).

Follow-up questions
  • Why should you avoid importing from conftest.py directly?
Confidence check

If you can confidently answer the pytest Essentials questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

2. Python Language for Test Code

Medium Common 1 minQ5 / 8

Q5.What is the mutable default argument bug?

Detailed explanation

Short answer: default values are created once, when the function is defined. A list default is therefore shared between calls.

def add_tag(tag, tags=[]):        # bug
    tags.append(tag)
    return tags

print(add_tag("smoke"))  # ['smoke']
print(add_tag("api"))    # ['smoke', 'api']  - leaked from the first call

def add_tag_fixed(tag, tags=None):
    tags = [] if tags is None else tags
    tags.append(tag)
    return tags

In test helpers this shows up as data leaking between tests, which only fails when tests run in a certain order.

Medium Occasional 1 minQ6 / 8

Q6.Write a context manager that times a block of test code.

Detailed explanation

Short answer: use contextlib.contextmanager; the code after yield runs on exit, including when an exception is raised if you use try/finally.

import time
from contextlib import contextmanager

@contextmanager
def timed(label):
    start = time.perf_counter()
    try:
        yield
    finally:
        print(f"{label}: {time.perf_counter() - start:.2f}s")

with timed("checkout flow"):
    run_checkout()
Follow-up questions
  • What does the with statement call on a class-based context manager? (__enter__ and __exit__)
Easy Occasional 1 minQ7 / 8

Q7.What must you set on every requests call in API tests?

Detailed explanation

Short answer: a timeout. The requests documentation states that requests do not time out unless you set one, so a hung server can block a CI job until the job itself is killed.

r = session.post(f"{BASE_URL}/orders", json={"sku": "A1", "qty": 1}, timeout=(3.05, 15))
assert r.status_code == 201, r.text
order = r.json()
assert order["qty"] == 1

The tuple means 3.05 s to connect and 15 s to read. Putting r.text in the assertion message shows the server's error body when the check fails.

Common mistakes
  • Asserting on r.json() before checking the status code
Medium Occasional 1 minQ8 / 8

Q8.When would you use a generator in test code?

Detailed explanation

Short answer: when you want values one at a time without building a full list - for example unique test users, or reading a large CSV line by line.

import itertools

def unique_emails(prefix="qa"):
    for n in itertools.count(1):
        yield f"{prefix}+{n}@example.com"

emails = unique_emails()
print(next(emails))  # qa+1@example.com
print(next(emails))  # qa+2@example.com

With pytest-xdist, add the worker id to the prefix so parallel workers never produce the same email.

RelatedQ6
Confidence check

If you can confidently answer the Python Language for Test Code questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Quick revision

  1. Q1: How do pytest fixtures work, and what does yield do inside one — Short answer: a fixture is a function that prepares something a test needs; tests ask for it by naming it as a parameter.
  2. Q2: How do you run one test with many inputs using parametrize — Short answer: @pytest.mark.parametrize runs the test once per row.
  3. Q3: How do you group and select tests with markers — Short answer: tag tests with @pytest.mark.smoke , register the marker in config, then select with -m .
  4. Q4: How do you share a fixture across files, and where does conftest.py apply — Short answer: a fixture in conftest.py is available to every test in that folder and its subfolders.
  5. Q5: What is the mutable default argument bug — Short answer: default values are created once, when the function is defined.

Frequently asked questions

1.What is expected from a Python SDET with 3 years of experience?
Solid pytest (fixtures, scopes, parametrize, markers, conftest), clean Python (context managers, generators, common bugs) and reliable API testing with requests. Async code and framework architecture are usually senior topics.
2.How is this page different from the senior Python page?
This page covers writing good tests. The senior page covers designing the framework: concurrency, parallel isolation, plugins, typing and how to lead flaky-test work.

Python jobs hiring now

Live, indexable Python openings — updated daily in Jobs Radar.

Browse all QA jobs on Jobs Radar

Loading current openings…

Home