Course outline

DevOps QA / Basic: delivery evidence and suite design / Lesson 3

Unit, component, and browser suites in CI

Choose a test boundary that reveals the intended defect and gives maintainers a useful failure location.

About 5 min readContent reviewed
On this page

Lesson goals

  • Match assertions to unit, component, and user-journey boundaries.
  • Keep browser tests focused on observable behavior and controlled dependencies.

State what is real in each suite

A unit suite isolates a small rule; a component suite exercises a larger deployable or service boundary with selected real dependencies; a browser suite drives the visible application. Teams use these names differently, so document the actual boundary and what is replaced. A booking rule tested with an in-memory fake cannot establish database locking behavior. A browser happy path cannot efficiently diagnose every numerical edge case. Combine layers so most detailed rule failures are localized, while a few representative journeys verify that the assembled system supports the user task.

Check a rule with discriminating inputs

A useful unit case distinguishes correct behavior from a plausible implementation mistake. Boundary values such as zero seats, exact remaining capacity, and one above capacity are more informative than repeating the same ordinary case with different names. Assert outcomes rather than private call counts unless the interaction itself is the contract. Keep time, randomness, and external services out of pure rule tests. The example models a simple capacity rule only; real authorization, concurrency, and persistence belong in additional tests at their relevant boundaries.

python A self-contained Python capacity example
import unittest

def can_reserve(remaining, requested):
    return requested > 0 and requested <= remaining

class CapacityTests(unittest.TestCase):
    def test_boundaries(self):
        self.assertFalse(can_reserve(4, 0))
        self.assertTrue(can_reserve(4, 4))
        self.assertFalse(can_reserve(4, 5))

if __name__ == "__main__":
    unittest.main()

This uses the Python standard library and no service. It is displayed as non-runnable course code; maintainers can verify it in a temporary local directory with python -m unittest. The test does not claim atomic capacity enforcement under concurrent requests.

Exercise integration without unnecessary reach

A component suite can call the application boundary with a real temporary database while substituting an external mail service. Specify which substitutions could hide defects and add separate evidence for them. Build fixtures through supported interfaces or explicit test helpers rather than production data. Reset state at a scope that matches test isolation. A test that proves the repository and schema work together should not require a public network dependency. Keep startup readiness separate from business assertions so an unavailable component is classified accurately instead of producing dozens of misleading assertion failures.

Drive a user-visible journey

Use stable accessible locators and assertions that wait for observable state rather than fixed delays. A browser context isolates cookies and local storage, but not necessarily the server-side account or booking records. Seed an owned record and clean it by identity. Keep a small critical journey such as making a reservation and reading confirmation, then cover detailed validation cheaper below the UI. The example assumes a controlled local demo application and deliberately avoids any public service. Its button names form part of the accessibility contract as well as the test locator.

typescript A Playwright Test journey for a local fixture
import { test, expect } from "@playwright/test";

test("booking confirmation is visible", async ({ page }) => {
  await page.goto("/workshops/demo-owned-session");
  await page.getByLabel("Seats").fill("1");
  await page.getByRole("button", { name: "Reserve" }).click();
  await expect(page.getByRole("status")).toHaveText("Reservation confirmed");
});

Requires a pinned compatible Playwright Test project, installed matching browser binaries, a local baseURL, and an isolated seeded workshop. demo-owned-session is a synthetic fixture id. This is not a complete application setup, and no browser or service is launched by the course.

Keep the suite map reviewable

Each suite needs an owner, expected duration range, environment contract, report format, and failure route. Avoid duplicating every scenario in every layer; duplication increases maintenance and can amplify one root cause into many red jobs. Review escaped failures to find a missing boundary rather than reflexively adding a browser test. UI snapshots and coverage can add evidence but do not replace behavioral assertions. A useful suite architecture gives both confidence in important tasks and a short path from a failed check to the responsible behavior or infrastructure condition.

Common errors and fixes

A fake-backed suite misses a locking defect

Why it happens
The fake does not reproduce database concurrency semantics.
How to fix it
Add a controlled concurrent test against the intended store.
Prevent it next time
Document real and substituted dependencies per suite.

A browser check fails only on slow runners

Why it happens
A fixed sleep substitutes for readiness.
How to fix it
Wait on the relevant visible or application state.
Prevent it next time
Use supported waiting assertions and bounded timeouts.

One outage creates dozens of product failures

Why it happens
Environment readiness is mixed with business assertions.
How to fix it
Classify setup failure and preserve its root evidence.
Prevent it next time
Separate fixture startup from scenario evaluation.

Check your understanding

1. Which test should prove that two simultaneous requests cannot oversell the final seat?

Show worked solution

Use a controlled concurrency integration test through the actual reservation and persistence boundary. The pure rule test remains valuable but cannot prove atomicity. Verify accepted and rejected outcomes plus the final stored capacity, and make scheduling reproducible enough to investigate failures.

2. A browser suite repeats forty numerical validation cases. Propose a smaller structure.

Show worked solution

Move detailed boundary combinations to unit or API tests and retain representative UI cases that prove errors are shown and submission is controlled. Keep at least one successful end-to-end journey. Confirm the lower layer owns the same validation rule rather than testing a duplicate rule unrelated to the UI.

Key takeaways

  • A test proves behavior only within its actual boundary.
  • Layered suites should improve diagnosis rather than duplicate counts.
  • Browser isolation does not automatically isolate backend data.

Official references