Skip to main content
White box testing and internal software behaviour
Sten Laidoner
Sten Laidoner|July 8, 2026|Reading time: 11 min read

What Is White Box Testing?

A practical introduction to white box testing, including code coverage, decision coverage, basis path testing, fault injection and mutation testing.

White box testing looks at software from the inside.

Instead of only checking what a user enters and what the system returns, the tester also understands something about the internal structure of the product. That may include the source code, application architecture, integrations, internal logic, data flows or API communication.

The purpose is to check whether the system works correctly internally, not only whether the final result looks correct to the user.

This is what separates white box testing from black box testing. Black box testing focuses on visible behaviour. White box testing looks deeper into how that behaviour is produced.

Why is white box testing performed?

One of the main reasons for white box testing is coverage.

Black box testing can show that a feature works correctly for a number of inputs and scenarios, but it cannot always tell you which parts of the internal logic were actually executed.

Imagine a feature containing several conditions, fallback paths and error-handling branches. The main user flow may work perfectly while a less common branch of the code has never been tested.

White box testing helps identify these gaps and can also help teams find defects earlier. A problem discovered during unit or integration testing is usually easier to investigate than the same problem found after several systems have already been connected together.

For example, imagine that a requirement says one thing while the acceptance criteria describe slightly different behaviour. Finding that conflict before the feature is fully developed can save a lot of unnecessary work.

White box testing also builds confidence in the internal behaviour of a system. Testing at several levels using different techniques gives the team more information about where risk may still exist.

Where is white box testing used?

White box testing can technically be used at several testing levels. In practice, it is most commonly associated with:

  • Unit testing
  • Component testing
  • Integration testing

Unit tests often check individual functions or pieces of logic. Integration testing looks at how components communicate with each other. Both can require knowledge of the internal application structure.

Many development teams also measure code coverage. Code coverage gives an indication of how much executable code has been exercised by tests, and some CI/CD pipelines include coverage checks before changes are allowed to move further through the development process.

However, a high coverage percentage does not automatically mean the software is well tested.

You can execute a line of code without properly testing the behaviour around it. Coverage is useful information, but it should not become the only goal.

White box testing techniques

There are several ways to approach white box testing. The chosen technique normally depends on the code, architecture and risk of the feature being tested.

Statement coverage

Statement coverage checks whether executable statements in the code have been run during testing.

A statement is simply a piece of code that performs an action. Consider this simple logic:

  • If age is 18 or higher → Show “You are eligible”
  • Otherwise → Show “You are under 18 and not eligible”

There are two executable outcomes. One test could use an age of 17 and expect the user to be shown as not eligible. Another could use an age of 19 and expect the user to be eligible.

By running both scenarios, we exercise both sections of the logic.

Statement coverage can be calculated as:

Executed statements ÷ Total executable statements × 100

For example, if 8 out of 10 executable statements were reached:

8 ÷ 10 × 100 = 80% statement coverage

Statement coverage is one of the most common forms of code coverage.

Decision coverage

Decision coverage focuses on the possible outcomes of decisions in the code.

This includes logic such as IF, IF / ELSE, CASE and SWITCH.

Using the same age example, the condition `age >= 18` has two possible outcomes: true or false.

  • Age 17 → False path → User is not eligible
  • Age 19 → True path → User is eligible

The decision coverage calculation is:

Executed decision outcomes ÷ Total possible decision outcomes × 100

In this example, both decision outcomes were executed:

2 ÷ 2 × 100 = 100% decision coverage

This looks simple in a small example. Real applications can contain many decisions where several conditions interact with each other, and that is where missed branches become much easier to hide.

Basis path testing

Basis path testing looks at the different execution paths through the code. The goal is to identify independent paths and create enough tests to exercise them.

Imagine a payment flow where the system checks several conditions:

  • Is the user authenticated?
  • Does the user have sufficient balance?
  • Is the payment destination valid?
  • Did the external payment provider accept the transaction?

Depending on the answers, the application can follow several different paths.

Testing only the successful payment path would leave most of the internal logic untouched. Basis path testing tries to cover the important routes through that logic using a controlled number of tests.

The goal is not to test every imaginable path blindly. It is to understand which independent paths carry meaningful risk.

API testing

API testing can also involve white box techniques, especially when the tester understands the internal service structure, data flow or business rules behind an endpoint.

Imagine an API request that creates a contract. The tester may know that the backend:

  • Validates the user
  • Checks the offer state
  • Validates the requested amount
  • Creates the contract
  • Changes the offer availability
  • Sends a notification

Testing only for a `200 OK` response would tell us very little.

White box knowledge helps the tester investigate each part of the process. Did the database state change correctly? Was the correct validation executed? Did the offer move to the expected state? What happens if the same request is sent twice?

This is where API testing becomes much more useful than simply checking response codes.

Fault injection

Fault injection deliberately introduces problems to see how the system behaves. Instead of waiting for a dependency to fail naturally, the failure is created intentionally.

Examples can include:

  • Database connection becomes unavailable
  • External API returns an error
  • Request times out
  • Service returns invalid data
  • Storage becomes unavailable

The tester then observes how the application responds. Does it recover? Does it retry? Does it return a useful error? Does it leave the system in a broken state?

Fault injection can reveal weaknesses that are difficult to find during normal functional testing.

Some forms of this testing may also be handled by security, platform or infrastructure teams depending on the product and team structure.

Mutation testing

Mutation testing tests the tests.

Small changes are intentionally introduced into the source code and the existing test suite is then executed.

Imagine the original logic is:

If age >= 18 → User is eligible

A mutation changes it to:

If age > 18 → User is eligible

The difference looks tiny, but an 18-year-old user would now incorrectly fail the eligibility check.

A good test suite should detect this change. If all tests still pass, there may be a gap in the test coverage.

The tests executed successfully, but they were not strong enough to notice that the business logic had changed.

That is the value of mutation testing. It measures how effective the tests are at detecting defects rather than only checking whether tests exist.

White box testing and the software development lifecycle

White box testing should be considered early in the software development lifecycle.

The planning stage is a good place to define important internal testing expectations:

  • Testing responsibilities
  • Code coverage expectations
  • Unit testing requirements
  • Integration testing needs
  • Critical internal flows

During requirements analysis, teams can already identify complex decision logic and important system states. During design, architecture and integration points become clearer, making it easier to decide which areas require deeper internal testing.

Most white box testing happens during development and the main testing phase, but it can also become important later.

Production issues may require developers and testers to investigate logs, code paths or internal service behaviour. Good documentation and existing tests can make these investigations much faster.

White box testing tools

The right tool normally depends on the programming language and testing technique.

Tools can support coverage measurement, API investigation, fault injection and mutation testing, but the tool should still match the testing problem.

Code coverage tools

  • Coverage.py: Measures which parts of Python code were executed and can help identify functions, branches or statements that were not reached.
  • JaCoCo: Commonly used to measure Java code coverage and can be integrated with build tools and CI pipelines.
  • Istanbul / nyc: Measures JavaScript code coverage and can report statement, branch, function and line coverage.

Modern CI systems and GitHub workflows can automatically generate coverage information whenever changes are pushed to a repository.

API testing tools

  • Postman: Supports request validation, collections, scripts and repeatable API checks.
  • Swagger and OpenAPI tools: Help testers understand endpoints, request structures and expected responses.
  • Insomnia: Useful for sending requests, managing environments and investigating API behaviour.

Fault injection tools

  • OneFuzz: A Microsoft fuzzing platform designed to help identify software defects through automated input testing.
  • Krkn: A chaos and resiliency testing tool used with environments such as Kubernetes and OpenShift.

Mutation testing tools

  • PIT: A Java mutation testing tool that modifies code and checks whether the existing test suite detects the changes.
  • Stryker: Provides mutation testing for several programming ecosystems and measures how many introduced mutations are detected by the tests.

Limitations of white box testing

White box testing can provide strong technical coverage, but it also has limitations.

The first is cost. Understanding internal logic and creating detailed tests can take time. Very large codebases can contain thousands of paths and conditions, and trying to test every internal detail is not always realistic.

Coverage targets can also create the wrong incentives. If a developer is told that a project must reach 90% code coverage, the easiest response may be to write tests that increase the number. That does not always mean the tests are useful.

A test can execute code without checking the right behaviour.

White box testing can also expose knowledge differences inside QA teams. Some testers may be comfortable reading code, investigating APIs and understanding architecture. Others may specialise more strongly in exploratory or user-focused testing.

Neither skill set is automatically more valuable. The problem starts when responsibilities are unclear or one type of testing is treated as a replacement for every other type.

White box and black box testing answer different questions. Strong QA often needs both.

White box testing looks beneath the visible result

White box testing uses knowledge of the internal system to create deeper and more targeted tests. It can help teams investigate code paths, decisions, integrations and failure handling.

Techniques such as statement coverage, decision coverage, basis path testing, fault injection and mutation testing all look at the system from slightly different angles.

The biggest advantage is visibility.

Instead of only asking whether a feature works, white box testing can help explain which parts of the system were actually tested and where internal risk may still remain.

But code coverage alone is not quality.

The goal should always be meaningful tests that help the team understand the product better.

Need practical QA support?

Laidoner Solutions helps software teams with manual QA, API testing, localization review, release checks and clear defect reporting.

Contact Us