Back to Courses
PYTHON + PYTEST — FROM BEGINNER TO AUTOMATION ENGINEER

Python for Test Automation

Learn Python the right way — understand what you are typing, why it works, and how it fits into real automation projects. Every concept explained before the code is shown.

35+
Days of Training
14
Modules
100+
Topics Covered
100%
Interview-Ready

Who Is This Course For?

This course is for testers and career switchers who want to learn Python without drowning in theory. Every topic is explained in plain language first — then you see the exact syntax. You will leave knowing not just how to write Python, but why each feature exists and how it directly helps you write better automated tests.

Python 3OOPPytestopenpyxlpandasJSONAllure

Your Learning Roadmap

01
Python Basics, Types & Operators
02
Collections, Loops & Functions
03
Functional & OOP Programming
04
Pytest, Fixtures & Data Handling
05
Full Automation Framework — Job Ready
Course Modules
1
Introduction & Python Setup
Why This Module
Python does not need a "build" step before running — you write code, hit run, and it executes immediately. This makes it much faster to learn and experiment with than languages like Java. Understanding the setup properly means you will never waste a day fighting installation issues when you could be writing actual code.
Getting Your Environment Ready
  • Installing Python 3 and configuring the PATH so you can run it from anywhere on your computer
  • Setting up PyCharm IDE — creating your first project and running a .py file
  • Understanding compiled vs interpreted — why Python runs without a separate compile step
  • What "exit code 0" means — your program finished without errors
  • Python's family tree: CPython (standard), Jython, PyPy, Brython — and why CPython is what we use
2
Python Fundamentals — Variables, Keywords & Data Types
Why This Module
Everything in programming comes down to storing and manipulating data. Before you can write a test that checks a username or validates a price, you need to understand how Python holds different kinds of information — numbers, text, yes/no answers, and "nothing at all". These are the atoms every program is built from.
Variables & Naming Rules
  • A variable is a labelled box — age = 25 puts the number 25 in a box called "age"
  • Identifier rules: letters, digits, underscore only; cannot start with a digit; case-sensitive
  • Python's 35 reserved keywords: if, else, for, while, def, class, return, pass — you cannot use these as variable names
  • Constants by convention: MAX_RETRIES = 3 — all caps signals "don't change this"
Built-in Data Types
  • int — whole numbers; float — decimals; complex3+4j (rarely needed in testing)
  • boolTrue or False: the result of every comparison in your tests
  • str — text in single, double, or triple quotes: your API responses, usernames, messages
  • None — means "nothing" or "not set yet" — common in API responses for missing fields
  • type(x) — tells you what kind of data x holds; input() — always returns a string, cast with int()
3
Data Collections — Choosing the Right Container
Why This Module
Real programs don't work with one value at a time — they process lists of users, sets of test IDs, tables of test data, and records with labelled fields. Python has a built-in container for each of these shapes. Picking the right one from the start prevents bugs and makes your code easier for teammates to read.
Python's Seven Container Types
  • list[1, 2, 3]: ordered, changeable, allows duplicates — your default go-to for sequences
  • tuple(1, 2, 3): ordered, locked (immutable) — use when data must not change
  • set{1, 2, 3}: no order, no duplicates — perfect for unique test IDs
  • frozenset — same as set but locked — used as dictionary keys
  • dict{"name": "Bhanu"}: lookup by label — like a row of test data with named fields
  • rangerange(1, 10): a lazy sequence of numbers — drives loops without storing all values
  • str — text is also a sequence — every character has an index and can be iterated
4
Operators & Expressions
Why This Module
Every assertion in a test is a comparison — "is this value equal to what I expected?" Every test condition is a logical combination — "did the login succeed AND was the right page loaded?" Operators are the language of assertions. You cannot write a meaningful test without them.
Arithmetic & Assignment
  • Standard maths: + - * /; integer division: //; power: **; remainder: %
  • Shortcut update: count += 1 instead of count = count + 1
  • String joining: "Hello " + name; repeating: "-" * 30 (separator lines in reports)
Comparison, Logical & Membership
  • Compare: == != > < >= <= — every comparison returns True or False
  • Combine conditions: and (both must be true), or (at least one), not (flip)
  • Check existence: "admin" in roles — one-line membership check on any container
  • Identity vs equality: is checks if two variables point to the exact same object; == checks if values match
5
Control Flow — Conditions & Loops
Why This Module
A program that always does the same thing regardless of input is not very useful. Conditions let your code branch — "if the status code is 200, check the body; otherwise log an error." Loops let you run the same check against 500 test records without writing 500 lines. These two ideas power almost everything in automation.
Conditional Statements
  • if condition: — run this block only when the condition is true
  • if-else — two paths: one for true, one for false
  • if-elif-elif-else — check multiple conditions in order; stop at first match
  • Nested if — condition inside a condition, like checking age AND nationality
Loops & Control
  • for item in collection: — go through every item; for i in range(n): — repeat n times
  • while condition: — keep going until the condition becomes false
  • break — exit the loop immediately (found what you needed); continue — skip this one, go to next
  • Nested loops — a loop inside a loop, used for comparing every pair in two lists or printing pattern grids
  • print(end="") — print without adding a new line, useful for same-row output in nested loops
6
Lists, Tuples & List Comprehension
Why This Module
Lists are the workhorse of Python automation — you will use them to hold API response items, test data rows, error messages, and user IDs. Knowing how to slice, sort, and transform a list in a single readable line is one of the skills that immediately separates an intermediate Python developer from a beginner.
List Access & Slicing
  • Indexing: items[0] is first, items[-1] is last — negative index counts from the end
  • Slicing: items[1:4] gives elements at positions 1, 2, 3 (end is exclusive)
  • Step slicing: items[::2] — every other element; items[::-1] — reversed copy
  • Quick stats: len(), min(), max(), sum(), sorted() — no loops needed
List Methods
  • Add: append(x) at end; insert(i, x) at position; extend(list2) merge
  • Remove: remove(x) by value; pop(i) by index and returns it; clear() empties list
  • Organise: sort() in place; reverse() in place; copy() to avoid changing original
  • Search: count(x) — how many times x appears; index(x) — where x first appears
List Comprehension & Unpacking
  • [x*2 for x in numbers] — create a transformed list in one line instead of a 4-line loop
  • [x for x in numbers if x > 0] — filter and collect in one line
  • Unpacking: a, b, *rest = my_list — grab first two items; everything else goes into rest
  • Tuples: same indexing as lists but immutable — use when you need to guarantee data won't change
7
Strings, Sets & Dictionaries
Why This Module
In test automation, you are constantly working with text — cleaning API responses, checking that a message contains a keyword, splitting a CSV line. Dictionaries are how JSON objects land in Python — every API response you parse becomes a dictionary. Mastering these three types means you can handle almost any data that real-world APIs throw at you.
String Operations
  • Case change: upper(), lower(), title() — normalise user input before asserting
  • Check type: isalpha(), isalnum(), isnumeric() — validate field content
  • Search: startswith("https"), endswith(".json"), find("error"), count("a")
  • Clean: strip() removes leading/trailing whitespace — essential for data from files
  • Split/join: "a,b,c".split(",")["a","b","c"]; ",".join(list) → back to string
  • f-strings: f"Status: {code}" — insert variable values directly into text; the cleanest formatting approach
Sets — Unique Collections
  • Sets automatically remove duplicates — pass a list with repeats to set() to deduplicate instantly
  • add(), remove(), discard() (no error if missing), pop(), clear()
  • Set maths: union() (all of both), intersection() (shared only), difference() (in A not B)
Dictionaries — Named-Field Records
  • Create: {"username": "bhanu", "role": "admin"} — each JSON object you parse becomes this
  • Safe read: d.get("key") returns None instead of crashing when key is missing
  • Loop: d.keys(), d.values(), d.items() — iterate over what you need
  • Counting pattern: d[key] = d.get(key, 0) + 1 — count occurrences without a separate counter per item
8
Functions — Writing Code Once, Using It Everywhere
Why This Module
Copy-paste coding is the fastest way to create bugs that are impossible to fix — because when you find an error you have to fix it in 30 places. Functions are the cure: write the logic once, give it a name, call it wherever you need it. Change the logic once and every caller gets the fix automatically. This is the foundation of maintainable test code.
Defining & Calling
  • def login(username, password): — define; login("bhanu","pass123") — call
  • Positional arguments — order determines which value goes where
  • Keyword arguments — login(password="pass", username="bhanu") — order does not matter
  • Default values — def greet(name="Guest"): — caller can skip it when default is fine
  • Variable number of arguments — *args packs any number of extras into a tuple
Return Values & Recursion
  • return result — send a value back to the caller
  • return a, b — send back multiple values as a tuple; unpack with x, y = func()
  • Recursive function: solves a problem by calling itself with a smaller version — useful for tree/nested structures
  • Python stops recursion at ~996 calls to prevent infinite loops — always define a base case that returns without calling itself
9
Functional Programming — Lambda, Filter, Map, Reduce & Generators
Why This Module
Once you can write functions, Python gives you a set of power tools for processing collections — filter a list without a loop, transform every item in one line, reduce a whole list to a single result. Senior Python developers use these constantly because they produce shorter, clearer, and faster code. Interviewers test these topics directly.
Lambda & filter() / map()
  • Lambda: lambda x: x > 0 — a tiny throw-away function with no name, used inline
  • filter(lambda x: x > 0, numbers) — keep only items where the condition is true
  • map(lambda x: x * 1.1, prices) — apply a transformation to every item (e.g. add tax)
  • Both return lazy objects — wrap with list() to see the result
  • When to use list comprehension vs filter/map — comprehensions are more readable for simple cases
reduce() & Generators
  • from functools import reduce; reduce(lambda a,b: a+b, nums) — collapse a list to one value
  • Use reduce for: total, product, max of a list, concatenating words
  • Generator function: uses yield — produces one value at a time instead of building the whole list in memory
  • Generator expression: (x for x in data if x > 0) — same as list comprehension but memory-efficient
  • Why generators matter in testing: stream through 100,000 test records without loading them all into RAM
10
OOP — Classes, Objects & Constructors
Why This Module
When your test suite grows beyond 10 files, you need a way to bundle related data and actions together. Classes are that way. Your BaseClass, your Page Object classes, your POJO data classes — all of these are real-world OOP. Understanding how classes and objects actually work is the difference between copying a pattern and truly owning the framework.
Creating Classes & Objects
  • Class = blueprint; Object = a copy made from the blueprint: obj = MyClass()
  • __init__(self, params) — runs automatically the moment you create an object; sets its starting values
  • self — every method receives the object itself as first argument so it can access its own data
  • Instance attribute: belongs to one object; class variable: shared by all objects of that class
Methods & Special Methods
  • Instance method: def validate(self): — called on an object; operates on its data
  • @classmethod — bound to the class, not an instance; receives cls instead of self
  • __str__(self) — controls what print(obj) shows; override to display meaningful info instead of a memory address
  • type(obj) — which class it came from; id(obj) — its unique memory address
11
OOP — Encapsulation & Inheritance
Why This Module
Two of the most powerful ideas in object-oriented programming: hiding sensitive data so it can only be changed through safe methods (encapsulation), and sharing behaviour across classes without rewriting it (inheritance). The BaseClass pattern used in every professional test framework — including the one you built in the REST Assured course — is inheritance in action.
Encapsulation — Hiding Data
  • Public by default — any code can read or change your object's attributes
  • Private with __: self.__balance — only accessible through methods of the same class
  • Why it matters: a Bank Account's balance should only change via deposit() and withdraw(), never directly
  • Python name mangling: __balance is internally renamed to _Account__balance
Inheritance — Sharing Behaviour
  • class Child(Parent): — Child gets everything Parent has automatically
  • Method overriding: Child redefines a method to behave differently — same name, different body
  • Multiple inheritance: class C(A, B): — gets from both parents; Python resolves conflicts left to right (MRO)
  • Call parent constructor explicitly: Parent.__init__(self) when child has its own __init__
12
Abstract Classes & Exception Handling
Why This Module
Abstract classes are how system architects enforce contracts — they say "anyone who builds from this must implement these features." Exception handling is how your tests stay alive when something goes wrong. Without it, one network hiccup crashes your entire test run. These are two of the most-tested topics in Python interviews.
Abstract Classes — Enforcing Contracts
  • from abc import ABC, abstractmethod
  • class Animal(ABC): — abstract class cannot be instantiated directly
  • @abstractmethod def make_sound(self): pass — every subclass MUST implement this or Python raises an error
  • Real-world use: architect defines the required API, developers implement it for each product/platform
Exception Handling — Staying Alive
  • try: — put the risky code here (database calls, HTTP requests, file reads)
  • except ZeroDivisionError: — catch a specific type; except: — catch anything
  • finally: — this block ALWAYS runs, even after an exception — perfect for cleanup (close DB, logout, delete test data)
  • Reading a stack trace: Python prints the chain of function calls from bottom (where it happened) to top (where you started)
  • Pattern: open_connection() → try: do_work() → except: log_error → finally: close_connection()
13
Pytest Framework — Writing Professional Automated Tests
Why This Module
Pytest is the most widely used Python testing framework in the industry. It discovers and runs your tests automatically, continues running after a failure, produces clean reports, and has a powerful fixture system for setup and teardown. Everything you have learned in this course comes together here — OOP, functions, data files, and exception handling all feed into a professional test suite.
Test Discovery Rules
  • Files must be named test_*.py — Pytest only looks in these files
  • Functions must start with test_ — anything else is ignored; helpful for helper functions in the same file
  • Classes must start with Test with no __init__ method
  • Run from terminal: pytest (all tests) or pytest -v (verbose, shows each test name)
Assertions & Fixtures
  • assert response_code == 200 — one line to declare a test passes or fails
  • Pytest continues to next test after a failure — unlike a plain script that stops at the first problem
  • @pytest.fixture — marks a function as setup/teardown provider, not a test itself
  • autouse=True — applies the fixture to every test in scope without naming it as an argument
  • yield inside fixture: code before yield = setup (runs first); code after = teardown (always runs)
  • scope="function" / "class" / "module" / "session" — controls how often setup runs
conftest.py & Parametrize
  • conftest.py — place shared fixtures here and every test file in that directory can use them automatically
  • params=["apple","mango","banana"] in fixture — Pytest runs each test once per value; request.param gives you the current value
  • Fixture inside a BaseTest class — subclasses inherit it; same pattern as the Java BaseClass you already know
Allure Reporting
  • pip install allure-pytest; run pytest --alluredir=./results
  • allure serve ./results — opens a rich HTML report showing pass/fail, duration, timeline, and test steps
  • Why Allure matters: stakeholders and managers can read it — it is not just a developer console log
14
File & Data Handling — Excel, CSV & JSON
Why This Module
Test data almost never lives inside the test code itself — it lives in spreadsheets, CSV exports, or JSON files. And API responses always come back as JSON. This module gives you three essential skills: read Excel data into Python, loop over CSV rows as test inputs, and parse any JSON response into a Python object you can assert against.
Excel with openpyxl
  • import openpyxl — no Excel application needed to read .xlsx files
  • wb = openpyxl.load_workbook("testdata.xlsx") — open the file
  • sheet = wb["Sheet1"] — navigate to the right tab
  • sheet.cell(row, col).value — read any cell by row and column number
  • Always call wb.close() when done — good hygiene, prevents file lock issues
CSV with pandas
  • import pandas as pd; df = pd.read_csv("data.csv") — entire file loaded as a DataFrame
  • DataFrame = a table with named columns — like a spreadsheet in memory
  • df.to_dict(orient="records") — converts each row into a dictionary; loop through to drive parameterised tests
JSON Handling
  • import json; data = json.loads(response_string) — parse a JSON string into a Python dictionary
  • json.load(open("data.json")) — parse directly from a file
  • Type mapping: JSON object → dict; array → list; true/false → True/False; null → None
  • After parsing: data["city"] — access fields exactly like a regular Python dictionary
  • Why this matters: every API response you test in REST Assured/Requests arrives as JSON — Python instantly turns it into a dict you can assert against
Interview Preparation

Python Fundamentals Q&A

What is the difference between is and ==? Explain with an example. When does // give a different result than /? What is name mangling and why does Python use it?

OOP Interview Q&A

Explain encapsulation using a Bank Account example. What is Method Resolution Order in multiple inheritance? What makes a class abstract and why would you use one in a test framework?

Functional Programming Q&A

When would you use filter() over a list comprehension? What does yield do and why does it save memory? Show how reduce() finds the maximum value in a list.

Pytest Q&A

What is conftest.py and why is it better than duplicating fixtures? What is the difference between scope="function" and scope="session"? Show a fixture that uses yield for cleanup.