Web app testing

What is functional testing?

Key takeaways

  • Functional testing checks that software produces the expected output for a given input,

    the way a user experiences it.

  • Cover critical workflows first,

    then go deep.

  • End-to-end tests anchor functional coverage;

    unit and API tests support it.

  • Flaky tests and maintenance are the real cost,

    so design tests to be narrow, independent and deterministic.

Every check in your pipeline is green. Then a support ticket comes in: a customer can't finish checkout. Nothing crashed and nothing was slow. The button just didn't do what it was supposed to do.

Functional testing checks that software does what it's supposed to do: you give a feature or workflow an input and confirm you get the expected output. It tests the product the way a user or API client sees it (log in, add to cart, pay, get a receipt), not how the code is written underneath.

Thinking about who'll build and maintain your functional tests? See how one team runs 300+ tests in parallel on every PR, then book a demo to see what that looks like for your app.

What is functional testing in software testing?

Functional testing verifies software against its requirements: given this input, the system should produce this result. Any mismatch is a functional defect.

It answers one question: does this work the way it's supposed to? It doesn't ask how fast it works, how secure it is or how nice it looks. Those are non-functional questions (more on that below).

In practice, a functional test:

  1. Puts the app in a known state (a logged-in user with an item in the cart).
  2. Does something (clicks "Place order").
  3. Checks the result (an order confirmation appears, and the order shows up in the account's history).

That last step is the important part. A test that clicks through a flow without checking the outcome isn't a functional test. It's a tour.

Can you give an example of a functional test?

Here's a set of functional tests for a login form. Each row is one input and one expected result.

Test Input Expected result
Valid login Correct email and password User lands on their dashboard
Wrong password Correct email, wrong password "Incorrect email or password" error; user stays on login page
Empty fields Click "Log in" with both fields blank Both fields flagged as required; no request sent
Locked account Correct details for a locked account "Account locked" message with a reset link
Password reset Click "Forgot password," enter email Reset email arrives; link opens the reset form

No database tables, no function names: just what goes in and what comes out.

Functional vs. non-functional testing: what's the difference?

Functional testing checks what the software does. Non-functional testing checks how well it does it.

Functional testing Non-functional testing
Question it answers Does the feature work as required? How fast, secure, scalable or usable is it?
Example Checkout charges the card and shows a receipt Checkout responds in under 2 seconds with 5,000 concurrent users
Based on Functional requirements, user stories, business rules Performance, security, accessibility and reliability targets
Common types Unit, integration, end-to-end, regression, smoke, UAT Load, performance, security, usability, accessibility
Result Usually pass/fail Often a measurement against a threshold

You need both. But if a user can't complete the checkout, it doesn't matter how fast the page loaded.

Is functional testing black box testing?

Mostly, yes. Functional tests are designed from requirements and observed behavior, so the tester doesn't need to see the code. That's black box testing.

The line isn't strict. Unit tests are usually white box but still functional when they check a function's output against its spec. What makes a test functional is what it checks, not who writes it.

What are the types of functional testing?

Functional testing is an umbrella. These are the types you'll run into most, from smallest scope to largest:

  • Unit testing: Checks one function or module in isolation. Fast, and usually written by developers.
  • Integration testing: Checks that modules or services work together (the order service correctly calls the payment service).
  • API testing: Checks that endpoints return the right responses, enforce business rules and handle bad input. Fast and stable, and useful for rules that sit beneath a user workflow.
  • UI testing: Checks that interface elements behave correctly when a user interacts with them.
  • End-to-end testing: Checks complete user workflows across the UI, backend and third-party services, the way a customer uses them.
  • Smoke testing: A small set of checks that the core features work after a build or deploy.
  • Sanity testing: A quick check that a specific fix or change works, without retesting everything.
  • Regression testing: Reruns existing tests to confirm new changes didn't break what already worked.
  • User acceptance testing (UAT): Confirms the software meets business requirements, often with real users or stakeholders.
  • Exploratory testing: Testers use the product without a script to find bugs nobody thought to test for.

Our view: end-to-end tests should anchor your functional coverage, because they're the only tests that check what a user experiences. Unit and API tests catch problems earlier and cheaper, but a passing unit suite doesn't tell you checkout works.

How do you do functional testing, step by step?

Most teams follow some version of these six steps:

  1. Identify what to test. List the features, workflows and business rules that matter, starting from requirements or user stories.
  2. Define the inputs. Include valid data, invalid data (negative testing) and edge cases (empty fields, max lengths, expired cards).
  3. Define the expected outputs. Write down what should happen before you run anything.
  4. Write and run the test cases. Do it manually for new or unclear behavior, and automate anything you'll run more than a few times.
  5. Compare actual vs. expected results. Any mismatch is a potential defect.
  6. Report, fix and retest. File a reproducible bug report, fix it, and add or keep the test so it can't quietly come back.

What should functional testing cover first?

Cover your critical workflows first, then go deep. A functional test suite should protect three things:

  • Features: Individual capabilities, like "search returns results."
  • Workflows: Sequences of features that deliver value, like "add to cart → checkout → pay → confirmation."
  • Business rules: What's allowed and what's rejected, like permissions, pricing, validation and eligibility. When these break, users see things they shouldn't or get charged the wrong amount.

Workflows matter most. Knowing checkout works across payment methods and error states is worth more than knowing 500 features pass in isolation.

That's why we go broad before going deep. Map every major workflow, start with the 10–15 that get the most traffic, and rank the rest by risk: user activity, revenue impact, dependencies, security and compliance, how recently the code changed, and complexity. Add edge cases once the core paths are covered.

How QA Wolf writes a functional test

As a QA testing company, we write functional tests for web, mobile, Electron and Windows desktop apps every day, in Playwright and Appium. A few rules do most of the work.

Every test starts as an outline. Before writing code, we outline the test in Arrange-Act-Assert format as code comments. Here's what a checkout test outline might look like:

// Arrange:
// log in as a test user with a saved card
// add one in-stock item to the cart

// Act:
// open the cart and click 'Checkout'
// select the saved card
// click 'Place order'

// Assert:
// the confirmation page shows an order number
// the order appears in the account's order history with the correct total

// Cleanup:
// cancel the test order

One test, one behavior. A good AAA test proves one thing. Not two. Not five. Just one. If checkout and order history each need checking in depth, they get separate tests. When a narrow test fails, you know where to look.

Tests don't depend on each other. Each test sets up its own state. Helpers can prepare data, but they don't assert. The test decides what counts as success.

Unique data, then cleanup. Tests create uniquely named data so they don't collide when they run in parallel, and they delete what they create. Leftover data is one of the quietest causes of flaky tests.

A failure isn't a bug report until someone checks it. Every failure gets investigated and reproduced before anyone's notified. Real bugs go to the team as bug reports, and tests broken by product changes get fixed. That's what keeps a red build meaningful.

Which functional tests should you automate?

Automate anything you need to pass every time you ship:

  • Smoke tests that run after each deploy
  • Regression tests that protect existing features
  • Critical workflows: sign-up, login, checkout, payments, account management
  • API checks for request handling, responses, error states and contracts
  • Anything that runs daily or more often

Keep these manual:

  • Exploratory testing, where the goal is discovery
  • One-off investigation of a bug before the expected behavior is defined
  • Subjective judgments like visual design or copy quality

Once a behavior is stable and you know what "correct" looks like, automate it.

When should you run functional tests?

Match the test to the moment:

  • On every commit: Unit tests. They're fast enough not to slow anyone down.
  • On every pull request: Integration tests plus the end-to-end tests for critical workflows. Catch it before it merges.
  • Before each release: The full end-to-end regression suite. This is your final gate.
  • Nightly (or continuously): Everything, so problems introduced during the day surface without blocking individual PRs.

If feedback takes hours, developers stop waiting for it. Parallel runs are what let a full suite fit inside a PR check.

Why do functional test suites get flaky and slow, and how do you fix it?

Writing the first 100 tests is the easy part. Keeping 1,000 of them useful while the product changes is the hard part. Tests fail for three reasons:

  • Bugs. That's the job. A failure that catches a bug is a win.
  • Product changes. You redesigned checkout, so the checkout tests need updating. Expected maintenance.
  • Flakes. Timing issues, race conditions, shared data, unstable environments. Flakes train developers to ignore red builds, and then the suite stops protecting anything.

How to keep a suite healthy:

  • Design for determinism. Wait on conditions, not fixed delays. Use stable selectors and isolate test data.
  • Keep tests narrow. One behavior per test makes failures fast to diagnose.
  • Split fast and full suites. Run critical workflows on PRs and everything else nightly.
  • Make failures debuggable. Video, console logs, network traces and a clear error message turn a 30-minute investigation into a 3-minute one.

How do you measure functional test coverage?

Measure coverage by workflows protected, not lines executed. A useful coverage number answers: if this suite passes, what can we ship with confidence? "Checkout works across all payment methods and error states" is a better answer than "80% code coverage."

To measure it:

  1. List your critical workflows and business rules.
  2. Map each test to the workflow it protects.
  3. Look for workflows with no tests, and for workflows with five tests doing the work of two.
  4. Track the map over time. As features ship, does coverage keep up?

Should you build functional testing in-house or use a service?

Writing tests is a project. Maintaining them is a permanent job: every product change, flaky run and failure needs someone's attention. Done by hand, that job takes QA engineers or SDETs with time for test infrastructure, parallel runs and daily triage.

With an AI testing platform, testing stays in-house without a team built around it. With QA Wolf, anyone on your team can ask for a test from Claude Code, Codex, Cursor or any MCP client, and QA Wolf's agent writes it in open-source Playwright or Appium, for web, mobile, Electron and Windows desktop apps. On every pull request, QA Wolf selects the relevant tests and runs them in parallel. When one fails, the agent reproduces it: real bugs reach you as bug reports with video, steps and a trace, and broken tests get fixed automatically. The tests are standard code, so they're yours to keep.

A service makes sense when what's missing is QA strategy, not hours: nobody owns what to cover, how deep to go or whether the coverage is good enough. QA Wolf's Coverage-as-a-Service does all of this for you. Full-time QA engineers embed with your team, build a test strategy for your product, report on coverage quality and investigate every failure, and comprehensive coverage is guaranteed. (Our guide to QA outsourcing covers what to look for in any testing service.)

To see either on your own app, book a demo, or add QA Wolf to your agent and ask for your first test.

Frequently asked questions

  • What is functional testing in software testing?

    Functional testing checks that software behaves according to its requirements: for a given input, it produces the expected output. It focuses on observable behavior (what a user or API client sees), not on how the code is implemented. Common types include unit, integration, API, end-to-end, smoke and regression tests.

  • Is functional testing black box testing?

    Usually. Functional tests are designed from requirements and observed behavior, so testers don't need to see the code, which is the definition of black box testing. Unit tests are the exception: they're often written with knowledge of the code but still check functional behavior.

  • Can you give me an example of a functional test?

    A login test: enter a valid email and wrong password, click "Log in," and check that the "Incorrect email or password" message appears and the user stays on the login page. Each functional test pairs one input with one expected result.

  • What's the difference between functional testing and QA testing?

    QA (quality assurance) is the whole practice of making sure software is good enough to ship. It includes planning, reviews, functional testing, non-functional testing and process. Functional testing is one part of QA, focused on whether features and workflows work as required.

  • What's the difference between black box and white box testing?

    Black box testing checks behavior from the outside, without looking at the code: inputs go in, outputs get checked. White box testing uses knowledge of the code's internals to design tests, for example to exercise each branch of a function. Most functional testing is black box. Most unit testing is white box.

  • What are the best tools for automating functional testing?

    For end-to-end functional tests, open-source frameworks like Playwright (web) and Appium (mobile and desktop) are widely used, along with Selenium and Cypress. The bigger decision is who maintains the tests. QA Wolf's agent writes and maintains Playwright and Appium tests, so the code stays yours with no vendor lock-in.

More from the blog

All posts