All posts

Testing Basics · Part 7

Test design techniques: black-box, white-box and grey-box testing

ProvaLab team · · 6 min read

In Part 6 we learned how to write a test case. This part is about how to find the right ones. Testers group their techniques by one simple question: how much of the inside of the software can you see?

That gives three approaches: black-box, white-box and grey-box testing.

Black-box testing sees only inputs and outputs and tests like a user, using partitions, boundaries, decision tables and states. Grey-box testing sees some internals such as the database, APIs and logs. White-box testing sees the code and tests every line and branch, using statement, branch, condition and path coverage.

Black-box testing

In black-box testing you test without looking at the code. You know what goes in, what should come out, and what the requirements say. The inside is a closed box.

This is how users experience software, and it is how most QA testing is done. You need no programming knowledge, and the tests stay valid even when developers rewrite the code inside.

The main black-box techniques:

1. Equivalence partitioning

Split the inputs into groups the software should treat the same, and test one value from each group. A discount field that accepts 0–100% has three groups: below 0, 0 to 100, above 100. (More detail, with a diagram, in Part 6.)

2. Boundary value analysis

Test at and around every edge: -1, 0, 1, 99, 100 and 101 for that discount field. Mistakes like < instead of <= only show up at the exact boundary.

3. Decision table testing

When the result depends on combinations of conditions, list every combination in a table, and turn each row into a test. For example: new customer yes/no × order over 300 yes/no → free delivery yes/no.

4. State transition testing

Some features behave differently depending on what state they are in. A food order moves through clear states:

An order moves Placed, Accepted, Preparing, Out for delivery, Delivered. It can be Cancelled from Placed, Accepted or Preparing. Cancelling once it is out for delivery is not allowed and should be tested.

Draw the states and the allowed moves, then test:

  • Every allowed move: placed → accepted, preparing → cancelled, and so on.
  • The forbidden moves: can a customer cancel an order that is already out for delivery? They mustn't, and the app must say so clearly.

State transition testing is ideal for orders, payments, sign-in (locked after 3 wrong passwords?), subscriptions and any kind of workflow.

5. Use case testing

Test complete journeys the way a real user would: "A customer searches for pizza, adds two, applies a code, pays by card and tracks the delivery." Each use case has a main flow and alternative flows (the card is declined, the restaurant closes mid-order).

6. Pairwise testing

When many settings combine, testing every combination explodes. Three devices × three payment methods × two languages makes 18 combinations. Most bugs are triggered by one setting, or a pair of settings, so pairwise testing picks a smaller set where every pair appears at least once. Here, 9 tests cover every pair instead of all 18. Free tools such as PICT generate these sets for you.

White-box testing

In white-box testing you design tests by looking at the code itself. You read the logic and make sure every part of it is exercised. It is mostly done by developers, usually as unit tests (see Part 5).

The key white-box idea is code coverage: how much of the code your tests actually ran. Here is a small function from our delivery app:

def delivery_fee(order_total, is_member):
    fee = 40
    if order_total >= 300:
        fee = 0
    if is_member:
        fee = fee / 2
    return fee

Statement coverage

Has every line run at least once? One test is enough here:

def test_big_order_member():
    assert delivery_fee(400, is_member=True) == 0

Both if conditions are true, so every line runs. We measured it with pytest-cov:

Name          Stmts   Miss  Cover
delivery.py       7      0   100%

100% statement coverage, from one test. Sounds complete, but it isn't.

Branch coverage

Has every decision gone both ways? Each if can be true or false, and our single test only ever took the "true" side. Turn on branch coverage and the gap appears:

Name          Stmts   Miss Branch BrPart  Cover   Missing
delivery.py       7      0      4      2    82%   3->5, 5->7

3->5 means "the if on line 3 never skipped straight to line 5": we never tested a small order. Add one test where both conditions are false:

def test_small_order_non_member():
    assert delivery_fee(100, is_member=False) == 40
Name          Stmts   Miss Branch BrPart  Cover   Missing
delivery.py       7      0      4      0   100%

Now every decision has gone both ways. This is why branch coverage is a stronger measure than statement coverage.

Condition and path coverage

  • Condition coverage checks each part of a combined condition separately, such as if is_member and order_total >= 300: has each half been both true and false?
  • Path coverage checks every route through the code. Our function has two ifs, so four paths: big+member, big+non-member, small+member, small+non-member. Our two tests cover only two of them. The small-order member case (fee 20) has never been tested.

Path coverage grows very fast with real code, so teams usually aim for good branch coverage and add path tests only for critical logic.

One warning: coverage tells you what code ran, not whether the tests checked the right things. A test with no assert still counts as coverage. Treat coverage as a map of what you haven't tested, not as proof of quality.

Grey-box testing

Grey-box testing sits in between. You test from the outside, like a user, but you use some knowledge of the inside (the database design, the APIs, the logs or the architecture) to design sharper tests and check results more deeply.

Examples from our app:

  • Check behind the screen: place an order in the app, then check the database. Is the order saved with the right total and status, or did the screen just show success?
  • Go around the UI: the app only lets customers choose quantities 1–10, but what does the API accept if you send 1,000 or -5 directly? Knowing there is an API makes this test possible.
  • Use the logs: trigger a failed payment and check the server logs for a clear error, with no card details written in plain text.
  • Integration points: knowing that orders are passed to the restaurant through a message queue, test what happens when that queue is slow or down.

Grey-box testing is common in integration, API and security testing, where knowing a little about the inside finds bugs a pure black-box tester would never reach.

Experience-based techniques

Alongside the three boxes, testers rely on experience:

  • Error guessing: "what usually breaks?" Empty fields, very long text, special characters, double clicks, the back button, a lost network.
  • Exploratory testing: learning, designing and testing at the same time, guided by curiosity and a time limit.
  • Checklists: a team's growing list of things that have gone wrong before.

Comparing the three

Black-box Grey-box White-box
Sees Inputs and outputs Some internals The code
Based on Requirements Requirements + architecture Code structure
Usually done by QA testers QA, automation, security Developers
Typical levels System, acceptance Integration, API, security Unit
Finds Missing or wrong behaviour Hidden data and integration problems Untested logic, dead code
Misses Untested code paths Very deep logic Missing features (you can't test code that was never written)

The last row matters most: each approach misses what the others catch. White-box testing can't find a feature nobody built, and black-box testing can't see a branch nobody reached. Good teams use all three.

What's next

In Part 8 we put it together in a test plan: what to test, how, by whom and when.

ProvaLab helps on every side of the box: Test Management keeps your black-box test cases, the coding agent writes and runs unit tests from the code, and API and security testing reach behind the UI. See it in the two-minute product tour.

Prefer to read offline? The whole Testing Basics series is one free PDF: get the PDF.

See ProvaLab working on a real app

Your coding agent runs the tests, reads the failures and fixes them.