Testing a Login Feature the Way You'd Actually Do It on the Job
A lot of QA content teaches testing techniques in isolation — here's equivalence partitioning, here's boundary value analysis, here's how to write a bug report. All useful, but it rarely shows how those pieces come together on a single, real feature.
So here's one walkthrough, start to finish: testing a login feature manually, at the API level, and with automation — the way you'd actually approach it with a sprint deadline, not in a vacuum.
The feature
A web and mobile app lets a user log in with an email and password. On success, they land on a dashboard. After 5 failed attempts within 10 minutes, the account locks for 15 minutes.
Simple on the surface. There's more here than "type password, click button."
Step 1: Manual test design
Before touching a keyboard, map out what actually needs checking:
- Happy path: valid email + valid password logs in successfully
- Boundary: exactly 5 failed attempts triggers lockout; 4 attempts does not
- Negative: wrong password, non-existent email, empty fields, SQL-injection-style input in the email field
- Session: does refreshing the page keep the user logged in? Does logging out on web also affect the mobile session?
- Mobile-specific: biometric login after the first successful password login, app backgrounded mid-login
That boundary case — exactly 5 attempts vs. 4 — is the kind of thing that's easy to skip if you're only thinking in terms of "test the lockout feature" rather than testing the number itself.
Step 2: API-level tests
UI tests are slow and brittle compared to hitting the API directly. Before automating anything visual, these are worth locking down at the API layer:
-
POST /loginwith valid credentials returns200and a token -
POST /loginwith invalid credentials returns401, not500 -
POST /loginsix times in a row returns423(locked) on the 6th attempt - A request with an expired token returns
401, not a silent failure
That third one matters more than it looks. A refactor that accidentally changes the lockout threshold, or breaks it entirely, is exactly the kind of regression that a UI-only test suite tends to miss — because the UI still looks fine right up until someone tries to actually break in.
Step 3: What to automate vs. keep manual
Not everything here deserves the same treatment.
The happy path and the lockout boundary are stable, high-value, and get exercised on every release — strong candidates for automation at both the API and UI level. A minimal Page Object for this might look like:
# pages/login_page.py
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
class LoginPage(BasePage):
EMAIL_INPUT = (By.ID, "email")
PASSWORD_INPUT = (By.ID, "password")
LOGIN_BUTTON = (By.CSS_SELECTOR, "button[type='submit']")
ERROR_MESSAGE = (By.CLASS_NAME, "error-message")
def login(self, email, password):
self.type_text(self.EMAIL_INPUT, email)
self.type_text(self.PASSWORD_INPUT, password)
self.click(self.LOGIN_BUTTON)
def get_error_text(self):
return self.find(self.ERROR_MESSAGE).text
# tests/test_login.py
def test_account_locks_after_5_attempts(driver):
login_page = LoginPage(driver)
driver.get("https://example.com/login")
for _ in range(5):
login_page.login("user@example.com", "wrong-password")
login_page.login("user@example.com", "correct-password")
assert "locked" in login_page.get_error_text().lower()
Meanwhile, usability observations — is the lockout message actually clear to a first-time user? — and one-off exploratory checks are better left manual. They rely on human judgment, not a pass/fail assertion, and automating them just gives you a brittle test that doesn't actually check the thing you care about.
Step 4: Prioritizing under time pressure
If a release is tomorrow and there's only time for a fraction of this list, the lockout boundary and the API-level auth checks go first. They protect account security, and they're exactly the kind of thing that quietly breaks when someone refactors the login service — and exactly the kind of bug that reaches production unnoticed if the only thing being checked is the UI happy path.
The pattern, generalized
Strip away the login specifics and the shape underneath is reusable for almost any feature:
- Design test cases across happy path, boundaries, and negative cases
- Identify what can be verified faster and more reliably at the API layer
- Decide what's actually worth automating vs. what needs a human's judgment
- When time is short, prioritize by what protects the business most, not what's easiest to test
That's the difference between "I know some testing techniques" and "I can design a test strategy for a real feature" — and it's the second one that actually gets asked about in interviews.
This walkthrough is adapted from a chapter in Breaking Into Software QA, a complete guide to breaking into software QA — manual and automated testing, API testing, mobile/Appium, real working automation code, and a full job search roadmap.
Top comments (0)