Mike Bennett

Deliverable

Test case suite — login and payment

Fourteen cases from the same fictional billing app, in the shape I write them: one behavior per case, preconditions stated, expected results specific enough to fail on. Twelve are automated in the demo repo; two stay manual on purpose.

Sample deliverable. Written for this site against a fictional product with no client data and no confidential material.

How I write these

  • One behavior per case. A case that tests three things fails ambiguously.
  • Preconditions stated, so the case is runnable by someone who did not write it.
  • Expected results specific enough to fail on. "Works correctly" is not an expected result.
  • Priority reflects business risk, not implementation difficulty.
  • Negative and boundary cases carry equal weight to happy paths — that is where the defects are.

Cases

IDCasePreconditionStepsExpected resultPriAutomated in
TC-AUTH-01Sign in with valid credentialsActive account, verified emailEnter registered email and correct password. Submit.Redirect to dashboard. Session cookie set with Secure and HttpOnly flags.P1test_auth.py
TC-AUTH-02Sign in with wrong passwordActive accountEnter registered email and an incorrect password. Submit.Generic failure message. Response must not reveal whether the email exists. No session created.P1test_auth.py
TC-AUTH-03Lockout after repeated failuresActive account, lockout threshold set to 5Submit an incorrect password five consecutive times.Sixth attempt is rejected regardless of password correctness. Lockout notice sent to the account email.P1test_auth.py
TC-AUTH-04Session expiry during an idle periodSigned in, idle timeout 30 minutesSign in, leave the tab idle past the timeout, then trigger an authenticated action.Action rejected, user returned to sign-in with the destination preserved. No unhandled error.P2Manual
TC-PAY-01First charge with a valid cardNew account, no stored payment method, sandbox processorSelect the monthly plan, enter a valid test card, confirm.Charge succeeds. Subscription active. Receipt email sent. Ledger webhook delivered exactly once.P1test_checkout.py, test_billing_db.py
TC-PAY-02Declined card at first chargeNew account, sandbox decline cardSelect the monthly plan, enter the decline test card, confirm.Clear decline message with the processor reason. No subscription created. No partial account state left behind.P1test_checkout.py
TC-PAY-03Double submission of the payment formNew account, valid test cardSubmit the payment form, then submit again before the first response returns.Exactly one charge. Second submission is idempotent, not a second authorization.P1test_checkout.py, test_billing_db.py
TC-PAY-04Card expiring before the next renewalActive subscription, stored card expiring within the billing periodAdvance the clock to the renewal date in the time-shifted environment.Renewal attempt fails cleanly, dunning sequence starts, account not suspended before the retry window closes.P2Manual
TC-PAY-05Card expiry in the past is rejected before submissionNew account, valid test card numberEnter a valid test card number and an expiry date in the past, for example 01/22. Confirm.Inline error shown for the expiry. No request is sent to the payment API.P2test_checkout.py
TC-PLAN-01Upgrade mid-cycle with prorationActive monthly subscription, 12 days into a 30-day periodChange to the higher-tier plan and confirm.Prorated charge matches the finance-supplied expected value to the cent. New tier effective immediately.P1test_plans.py
TC-PLAN-02Downgrade defers to period endActive higher-tier subscriptionChange to the lower-tier plan and confirm.No immediate charge or refund. Current tier retained until period end. Scheduled change recorded with its effective date.P2test_plans.py
TC-PLAN-03Upgrade mid-cycle in a 31-day monthActive monthly subscription, 12 days into a 31-day periodChange to the higher-tier plan and confirm.Prorated charge uses the real period length and matches the finance-supplied expected value to the cent.P1test_plans.py
TC-HOOK-01Duplicate webhook deliveryLedger consumer runningReplay an identical payment-succeeded event twice.Ledger records one entry. Duplicate acknowledged, not reprocessed.P1test_webhooks.py
TC-HOOK-02Malformed webhook payloadLedger consumer runningDeliver an event with a missing required field.Rejected with a 4xx and logged with the event ID. No partial write. No retry storm.P2test_webhooks.py

Automation

Each automated test names the case it covers, so a failing test points straight back at the manual case and its expected result. The two manual cases need the time-shifted environment, and nothing gets automated until it has run manually twice and stopped changing.


@pytest.mark.regression
@pytest.mark.known_defect("BUG-1156")
@pytest.mark.tc("TC-PLAN-03")
def test_upgrade_mid_cycle_prorates_a_31_day_period(api, token, clock):
    ...

Three of the cases fail on the release-candidate build because they reproduce the defects in the demo app: TC-PAY-03 (BUG-1142), TC-PLAN-03 (BUG-1156) and TC-PAY-05 (BUG-1163).

Import format

The same suite exports to Xray or Zephyr CSV without rework, because the columns above map directly onto their import fields. The full library is in the demo repository as docs/test-cases.csv.


Test Case ID,Summary,Precondition,Test Steps,Expected Result,Priority
TC-AUTH-02,Sign in with wrong password,Active account,"Enter registered email and an incorrect password. Submit.","Generic failure message. Response must not reveal whether the email exists. No session created.",P1