White Box vs Black Box Testing: Techniques, Differences & Test Data Preparation

Software Engineering · Chapter 31

White Box vs Black Box Testing: Techniques, Differences & Test Data Preparation

A program can return the right answer for the examples you tried and still contain an untested branch. It can also execute every branch while failing a real user requirement. Let us learn both ways of finding those gaps.

In this chapter
  1. The two views
  2. One common example
  3. Black box techniques
  4. White box techniques
  5. Test data preparation
  6. Runnable JavaScript example
  7. Key differences
  8. Exam answer and FAQs

Why do students mix up these two?

White Box vs Black Box Testing: Techniques, Differences & Test Data Preparation

The name “box” makes the concept sound difficult. Imagine you give a machine an input and observe its output. In black box testing, the test design comes from what the machine must do. In white box testing, we can also inspect how its internal logic is arranged and select inputs to exercise that logic.

View 01 · Requirements Black box

“For age 17, should the system reject the ticket request?” We can answer this from the specification.

View 02 · Structure White box

“Does our test take both the true and false exits of this if?” We inspect the implementation.

These are test design approaches, not fixed job titles or test levels. A developer can design a black box test, and a tester with code access can design a white box test. Both can be useful at more than one test level. If you want the broader testing picture, review software testing objectives and test levels.

Picture 1 · What information guides each test?
Both approaches run software and check results. Their difference is the information used to design the tests.

Our example: a simple ticket-price rule

Assume a college event sells a ticket to people aged 18 to 60, inclusive. A valid member pays ₹80; a valid non-member pays ₹100. Age must be an integer and membership must be a Boolean value (true or false). Any invalid input returns "INVALID".

Notice the phrase “inclusive”: 18 and 60 are accepted. A small mistake such as writing age > 18 instead of age >= 18 would reject a valid student. This is why we prepare boundary data before writing random test cases.

Black box testing techniques, with test data

We start from the rule above. We do not need to read the function code to derive these cases. This is called a specification-based way of designing tests. The four core techniques below are also covered in the ISTQB Foundation syllabus.

1. Equivalence partitioning: group similar inputs

Instead of trying every age, divide ages into groups that the rule is expected to handle in the same way: below 18, 18–60, and above 60. Use representative values such as 10, 35 and 75. Then include a separate invalid-type group, such as "35" or 18.5, because the requirement says age must be an integer.

Picture 2 · Age input partitions
Membership forms another input dimension: true, false, and invalid type. Testing just one valid age does not cover both valid membership outcomes.

Important: an equivalence partition is an assumption that inputs in a group behave similarly. If special rules exist within a group, split it further. The age partitions also do not replace tests for membership.

2. Boundary value analysis: test the edges

For the integer interval 18–60, test around both ends: 17, 18, 19 and 59, 60, 61. With membership set to false, the expected results are INVALID, 100, 100, 100, 100, INVALID. Values just beside the boundary reveal mistakes in comparison operators.

Picture 3 · The six useful edge values
All ages here are integers. For a different data type or rule, choose boundaries according to that specification.

3. Decision table testing: cover combinations of rules

There are two decisions: Is the input valid? and Is the person a member? A compact decision table makes the expected result explicit. “Either” means membership cannot change the outcome when the input is invalid.

Valid age and Boolean? Member? Expected result
NoEitherINVALID
YesYes₹80
YesNo₹100

For example, (35, true) should return 80, (35, false) should return 100, and (17, true) should return INVALID. For deeper practice with this technique, the idea connects to how requirements and software decisions are documented.

4. State transition testing: test change over time

The price function itself does not store a changing state. But in a full booking system, a seat may move from Available → Reserved → Booked. Test a valid transition, such as Available → Reserved, and an invalid action, such as trying to book the same seat again after it is already Booked. A test sequence matters here; one isolated age value cannot test it. To see how the complete workflow is tested when modules connect, read integration testing process and strategies.

White box testing: follow the code's control flow

Now the implementation is available. We can see a first if that rejects invalid input and a second if that selects the member price. We can choose data to execute both outcomes of those decisions.

Implementation under test · JavaScript
function ticketPrice(age, isMember) {
  if (!Number.isInteger(age) || age < 18 || age > 60 ||
      typeof isMember !== "boolean") {
    return "INVALID";
  }

  if (isMember) {
    return 80;
  }

  return 100;
}

The code matches our stated rule. A real white box test is still required, because source code can contain a branch no one exercised or a mistake that was overlooked while reading.

Statement coverage

A statement is an executable instruction. Statement coverage asks what proportion of executable statements ran at least once. In this small function, tests that return INVALID, 80 and 100 exercise all three return statements. Coverage is commonly expressed as executed statements ÷ total executable statements × 100, with the exact measurement produced by a coverage tool.

Executing a line does not prove that its result is correct. A test also needs an expected result and an assertion.

Branch coverage

A branch is a possible transfer of control. For our two if decisions, we want the invalid-input decision to be true and false, and the member decision to be true and false when reached. Three inputs can do that: (17, false), (35, true), (35, false).

Path A · (17, false)Invalid input: true

Return INVALID; second decision is not reached.

Path B · (35, true)Invalid input: false · Member: true

Return 80.

Path C · (35, false)Invalid input: false · Member: false

Return 100.

Extra risk case · (61, false)Invalid input: true for a different reason

Return INVALID; checks the upper boundary too.

Coverage is not correctness. These three paths exercise the main true/false outcomes, but they do not prove that each condition joined by || was independently tested. For example, if we never send age 61 or membership "yes", those rejection rules could still be broken. Also, 100% statement coverage need not imply 100% branch coverage.

At an advanced level, you may hear about condition, path and modified condition/decision coverage (MC/DC). These aim at different, often stronger obligations. The Foundation-level focus here is statement and branch testing; choose more rigorous criteria when the project risk or standard requires them.

Test data preparation: a practical step-by-step method

Test data means the inputs and starting conditions needed to execute a test. A useful test case also records its expected result. Writing “test invalid age” is too vague; age = 17, isMember = false, expected "INVALID" is repeatable.

1 · Read the rule

Write the allowed range, types, outcomes and any missing-input behaviour.

2 · List partitions

Choose representatives for valid, invalid, malformed and missing values.

3 · Add boundaries

For this integer rule: 17, 18, 19 and 59, 60, 61.

4 · Add combinations

Exercise member true and false; include an invalid type such as “yes”.

5 · Map code paths

After seeing the code, select data for each important branch.

6 · Record and reset

Write expected outputs, set up a known start state and clean up after tests.

A small test data sheet

TC01 · Below minimum17, false → INVALID

Immediately below the minimum.

TC02 · Minimum18, false → 100

First accepted age.

TC03 · Above minimum19, false → 100

First neighbour inside the range.

TC04 · Member rule35, true → 80

Valid age with member price.

TC05 · Non-member rule35, false → 100

Valid age with standard price.

TC06 · Below maximum59, false → 100

Last neighbour inside the range.

TC07 · Maximum60, false → 100

Last accepted age.

TC08 · Above maximum61, false → INVALID

Immediately above the maximum.

TC09 · Decimal age18.5, false → INVALID

Age must be an integer.

TC10 · Membership type35, "yes" → INVALID

Membership must be Boolean.

TC11 · Missing ageundefined, false → INVALID

Required input absent.

TC12 · Null membership35, null → INVALID

Null is not a Boolean.

In a database-backed test, a starting condition may be “seat A1 exists and is available.” Prepare that fixture before the test and reset it afterwards. Use synthetic or anonymised personal data where possible; never paste real user details into a public example or shared test log. Keep the expected result based on the requirement, rather than copying what the current code happens to return.

Runnable JavaScript test example

Copy this complete example into a ticket-test.js file and run it with Node.js. Each object stores an input and expected result; the reasons are listed in the test data sheet above. The check throws an error if any expected result is different from the actual result.

Specification cases + implementation + assertions
function ticketPrice(age, isMember) {
  if (!Number.isInteger(age) || age < 18 || age > 60 ||
      typeof isMember !== "boolean") {
    return "INVALID";
  }
  if (isMember) return 80;
  return 100;
}

const tests = [
  { id: "TC01", age: 17, member: false, expected: "INVALID" },
  { id: "TC02", age: 18, member: false, expected: 100 },
  { id: "TC03", age: 19, member: false, expected: 100 },
  { id: "TC04", age: 35, member: true,  expected: 80 },
  { id: "TC05", age: 35, member: false, expected: 100 },
  { id: "TC06", age: 59, member: false, expected: 100 },
  { id: "TC07", age: 60, member: false, expected: 100 },
  { id: "TC08", age: 61, member: false, expected: "INVALID" },
  { id: "TC09", age: 18.5, member: false, expected: "INVALID" },
  { id: "TC10", age: 35, member: "yes", expected: "INVALID" },
  { id: "TC11", age: undefined, member: false, expected: "INVALID" },
  { id: "TC12", age: 35, member: null, expected: "INVALID" }
];

for (const test of tests) {
  const actual = ticketPrice(test.age, test.member);
  if (actual !== test.expected) {
    throw new Error(
      `${test.id}: expected ${test.expected}, got ${actual}`
    );
  }
  console.log(`${test.id} passed`);
}

The black box part is the set of expected cases derived from the ticket rule. The white box part is checking which branches those cases execute and adding cases for missed logic. In a real project, use a test framework and a coverage tool to measure the latter; twelve passing cases alone do not tell you the coverage percentage. For the difference between an individual function test and a full module interaction test, see unit testing techniques and examples.

Black box vs white box testing: key differences

PointBlack boxWhite box
Design basisRequirements and observable behaviourInternal structure and control flow
Code knowledgeNot needed for test designNeeded to design structure-based tests
Example techniquesPartitions, boundaries, decision tables, statesStatement and branch testing
What it may revealMissing or incorrect required behaviourUntested code and faulty internal decisions
Typical gapInternal path may remain untestedRequired behaviour may still be missing

A strong test set often uses both views. For our example, boundary cases catch mistakes at ages 18 and 60, while branch-oriented cases make sure both member outcomes and invalid-input handling execute. Neither a large number of tests nor a high coverage number alone proves the product is defect-free.

Exam-ready answer and memory trick

5-mark answer:

Black box testing is a specification-based approach in which test cases are designed from requirements and expected external behaviour without referring to the program's internal structure. Its common techniques include equivalence partitioning, boundary value analysis, decision table testing and state transition testing. White box testing is a structure-based approach in which tests are designed from internal logic, such as executable statements and branches. For example, a ticket function accepting ages 18–60 can be tested with boundary values 17, 18, 60 and 61; its internal true and false branches can then be exercised using invalid, member and non-member inputs. Both approaches require prepared data and expected results and work well together.

Memory trick: Black = Behaviour visible outside. White = Working visible inside. For data preparation remember R-B-C-E: Rule, Boundaries, Combinations, Expected result.

Frequently asked questions

Does black box testing mean no one knows the code?

No. It means the tests are designed from the specification and observable behaviour without relying on internal structure. The person designing them may still have access to code.

Is white box testing only for unit testing?

No. Code-level statement and branch tests are common at unit level, but structural knowledge can also guide testing at other levels.

What is the difference between statement and branch coverage?

Statement coverage checks which executable statements ran. Branch coverage checks which control-flow branches ran. Running every statement does not necessarily exercise every branch.

What should test data contain?

Record the input values, starting conditions or fixtures, the expected result and the purpose of each case. Include valid, invalid, boundary, type and relevant combination cases.

Does 100% coverage mean the software has no bugs?

No. Coverage shows what was exercised according to one criterion. Incorrect assertions, missing requirements, particular data combinations and other defects can remain.

Technical reference: ISTQB Certified Tester Foundation Level Syllabus, section 4: Test Analysis and Design. The ticket rule, diagrams and test cases here are original learning examples.

Post a Comment

0 Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.
Join Telegram Exam updates and free resources