DEV Community

Aleksandr Singer
Aleksandr Singer

Posted on

Breaking Into Software QA

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 /login with valid credentials returns 200 and a token
  • POST /login with invalid credentials returns 401, not 500
  • POST /login six times in a row returns 423 (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
Enter fullscreen mode Exit fullscreen mode
# 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()
Enter fullscreen mode Exit fullscreen mode

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:

  1. Design test cases across happy path, boundaries, and negative cases
  2. Identify what can be verified faster and more reliably at the API layer
  3. Decide what's actually worth automating vs. what needs a human's judgment
  4. 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)