How do you know whether your testing covers enough of an application before it reaches users? Running hundreds of test cases may sound reassuring, but the number alone doesn't tell you whether important features, conditions, or user journeys have been tested.
This is where test coverage helps. It shows which parts of an application have been tested and, just as importantly, where testing gaps remain.
However, coverage is not just about percentages. A test suite can achieve high code coverage while overlooking critical scenarios, such as failed payments, invalid inputs, or problems that occur on specific devices.
In this guide, we'll explain what test coverage means, explore its different types, show how to measure it, and discuss practical ways to improve coverage without adding unnecessary tests.
What Is Test Coverage in Software Testing?
Test coverage in software testing measures how much of a defined aspect of an application has been covered by tests. That aspect might include software requirements, features, user scenarios, source code, or supported environments.
The purpose of test coverage is to identify what has been tested, what remains untested, and where additional testing may be necessary.
Consider an online shopping application with the following features:
- User registration and login
- Product search
- Shopping cart management
- Payment processing
- Order tracking
Suppose the testing team has created and executed test cases for four of these five features, leaving order tracking untested.
In this simplified example, feature coverage is 80%.
That number identifies a gap, but it does not tell us whether the four tested features were tested thoroughly. For instance, payment processing might have been tested only with successful transactions, leaving failed payments and refunds unverified.
This distinction matters because coverage measures the extent of testing, not necessarily its effectiveness.
Test coverage can also be measured at different stages. A requirement may have a test case written for it, but that test may not have been executed. Teams should distinguish between tests that have been designed, tests that have been run, and tests that have passed.
Why Test Coverage Matters (and Where It Misleads)
Test coverage helps development and QA teams understand how thoroughly they have tested an application against their defined testing objectives.
Instead of relying only on the total number of test cases or completed test runs, teams can use coverage information to identify specific gaps.
Why Test Coverage Matters
- Identifies untested areas Coverage reports can show which requirements, code branches, or application scenarios lack tests. Teams can then decide whether those gaps need additional attention.
2. Supports risk-based testing
Not all features carry the same level of risk. For example, incorrect payment calculations may have more serious consequences than a minor formatting issue on a settings page.
Coverage information helps teams focus testing efforts on the areas where failures would matter most.
3. Helps maintain regression coverage
As developers introduce new features or modify existing functionality, previously tested behavior may change. Reviewing coverage helps teams determine whether their regression tests still address the relevant requirements and scenarios.
4. Improves visibility into testing progress
Coverage metrics can help teams track which requirements have corresponding tests, which tests have been executed, and where work remains incomplete.
Where Test Coverage Can Be Misleading
The main limitation is that coverage does not prove that tests are effective.
Consider a function that calculates a customer's final bill. An automated test calls the function but never checks whether the returned total is correct.
The function may register as covered by a code coverage tool, even though the test cannot detect an incorrect calculation.
Other limitations include:
- A high percentage may hide missing negative or boundary scenarios.
- Coverage can increase without meaningful improvements in test quality.
- Different coverage metrics cannot be combined into one meaningful percentage without defining a common measurement method.
- Tests may pass in one environment but fail on another device, browser, or network.
Coverage should therefore be considered alongside test results, defect findings, business risk, and other relevant quality measures.
Test Coverage vs Code Coverage
Test coverage and code coverage are closely related, but they answer different questions.
Test coverage is the broader concept. It evaluates how much of a defined testing scope has been covered, such as requirements, functionality, scenarios, or environments.
Code coverage is a specific measurement of how much source code is executed while tests run.
Example: Login Functionality
- Suppose an application's login feature supports:
- Successful login with valid credentials
- Rejection of incorrect passwords
- Account lockout after repeated failed attempts
- Password reset
- Session expiration
A code coverage report may show that tests execute most of the login module.
However, the tests might cover only successful login and incorrect passwords, leaving account lockout, password reset, and session expiration untested.
The code coverage percentage may therefore look encouraging even though important user scenarios remain uncovered.
The key difference: Code coverage helps identify unexecuted code. Broader test coverage helps identify gaps in what the application is expected to do.
Both are useful, but neither replaces the other.
Types of Test Coverage
There are several types of test coverage, each examining a different aspect of an application.
1. Requirements Coverage
Requirements coverage measures how many requirements have corresponding test cases.
For example, a banking application might require users to receive a notification after completing a transaction. If no test case verifies this behavior, the requirement lacks test coverage.
A Requirements Traceability Matrix (RTM) can help teams connect individual requirements to test cases and execution results.
2. Functional Coverage
Functional coverage evaluates whether the application's defined features and behaviors have been tested.
Consider a food delivery application. Testing only successful order placement would not cover related functionality such as:
- Applying promotional discounts
- Cancelling an order
- Handling unavailable items
- Processing unsuccessful payments
Functional coverage helps identify which expected behaviors still require validation.
3. Scenario and User Journey Coverage
Scenario coverage focuses on specific situations and workflows that users may encounter.
For example, an airline booking application might need tests for searching flights, selecting seats, making payments, and receiving booking confirmations.
A complete booking journey also involves interactions between these steps, which may reveal issues that isolated feature tests miss.
4. Code Coverage
Code coverage measures which parts of the application's source code execute during testing.
Common code coverage metrics include:
These metrics are not interchangeable.
For instance, a test may execute every statement in a function without exercising every possible branch. Similarly, branch coverage does not necessarily demonstrate that every individual Boolean condition has been independently tested.
Complete path coverage can also become impractical when code contains many decisions or loops.
The exact metrics available depend on the coverage tool and programming language.
5. Boundary and Input Coverage
Boundary coverage checks whether tests address input limits and values around those limits.
Suppose a banking application allows users to transfer between ₹100 and ₹50,000.
Useful test inputs would include:
- ₹99, just below the minimum
- ₹100, the minimum permitted amount
- ₹101, just above the minimum
- ₹49,999, just below the maximum
- ₹50,000, the maximum permitted amount
- ₹50,001, just above the maximum
This approach helps teams find problems that may not appear when testing ordinary input values.
6. Device and Environment Coverage
Environment coverage measures which relevant device, browser, operating system, network, or deployment configurations have been tested.
For example, a mobile application might work correctly on one Android phone but encounter layout problems on a smaller screen or connection problems on a cellular network.
Environment coverage helps teams identify which supported configurations have been exercised. It is particularly important for applications used across different devices and regions.
How to Measure Test Coverage
Test coverage is commonly calculated by dividing the number of covered items by the total number of applicable items and multiplying by 100.
The general formula is:
Test Coverage (%) = (Covered Items ÷ Total Applicable Items) × 100
The important part is defining what counts as an item and what qualifies it as covered.
1. Calculate Requirements Coverage
Suppose a project has 40 requirements, and 32 have at least one corresponding test case.
Requirements Coverage = (32 ÷ 40) × 100 = 80%
This means 80% of the requirements have mapped tests.
It does not establish whether those tests have run or passed. Those results must be tracked separately.
2. Calculate Scenario Coverage
Consider an online banking application with 25 identified test scenarios. The team has executed tests for 20 distinct scenarios.
Executed Scenario Coverage = (20 ÷ 25) × 100 = 80%
The remaining five scenarios still require execution.
A separate pass-rate metric can show how many executed tests passed.
3. Calculate Statement Coverage
Suppose a code coverage tool identifies 200 executable statements, of which 170 execute during testing.
Statement Coverage = (170 ÷ 200) × 100 = 85%
This indicates that 30 executable statements were not exercised during the measured test runs.
4. Calculate Branch Coverage
Suppose an application's code contains 60 branches, and tests execute 45 of them.
Branch Coverage = (45 ÷ 60) × 100 = 75%
The remaining 15 branches represent execution paths that the measured tests did not exercise.
Comparing Different Coverage Metrics
These are hypothetical examples, not actual application test results.
Although the percentages appear similar, they measure different things. They should not be averaged together to produce a single overall coverage score.
How to Measure Coverage in Practice
A practical measurement process involves five steps:
- Define the testing scope. Identify the requirements, scenarios, code modules, or environments that matter.
- Choose appropriate metrics. Select measurements based on what the team needs to understand.
- Collect the data. Use code coverage tools, test management records, or execution reports.
- Review uncovered items. Determine whether gaps represent missing tests, unexecuted tests, or intentionally excluded scope.
- Track changes over time. Review the same metrics after significant application updates.
Consistent definitions and measurement methods make coverage reports more useful when comparing builds or releases.
Mutation Testing: Checking Whether Coverage Is Real
Traditional code coverage tools tell you whether tests execute code. They do not necessarily tell you whether those tests can detect incorrect behavior.
Mutation testing evaluates test effectiveness by deliberately introducing small changes into the code and checking whether the existing tests detect them.
These modified versions of the code are called mutants.
1. How Mutation Testing Works
Consider a function that checks whether a customer qualifies for a discount.
The original condition is:
orderTotal >= 1000
A mutation testing tool might change it to:
orderTotal > 1000
The difference matters when the order total is exactly 1,000.
If the test suite checks only values of 1,500 and 500, both conditions may produce the same results. The tests would execute the code but fail to detect the altered boundary condition.
A test using an order total of exactly 1,000, with an assertion for the expected discount eligibility, could detect the change.
2. Mutation Testing Outcomes
Mutation testing tools commonly classify mutants using outcomes such as:
- Killed: A test detects the mutation by failing.
- Survived: The mutation is not detected by the tests that exercise the affected code.
- No coverage: No applicable test exercises the mutated code.
- Timed out: Execution exceeds the allowed time, potentially because the mutation creates an infinite loop.
Some mutations are equivalent to the original code and do not change its observable behavior. These require care when interpreting results.
3. How to Calculate the Mutation Score
The mutation score measures the proportion of valid mutants detected by the test suite.
Mutation Score (%) = (Detected Mutants ÷ Valid Mutants) × 100
Suppose a mutation testing run produces 20 valid mutants. The tests detect 14, while six remain undetected.
Mutation Score = (14 ÷ 20) × 100 = 70%
This suggests that 30% of the valid mutations were not detected.
Tools may classify certain outcomes differently. For example, Stryker's mutation metrics count timed-out mutants as detected.
Mutation testing is particularly useful for business logic, calculations, and conditional behavior where tests need to check correct results rather than simply execute code.
It is best used alongside traditional coverage measurements, not as a replacement for them.
Device and Environment Coverage for Mobile and Web Apps
An application can have strong functional and code coverage while still behaving differently across devices, browsers, operating systems, or network conditions.
For mobile and web applications, device and environment coverage measures which relevant configurations have been exercised during testing.
What Should Environment Coverage Include?
The goal is not to test every possible combination. That would often require an impractical number of test runs.
Instead, teams should identify the configurations that matter most to their users.
For example, a mobile banking application might prioritize commonly used Android and iOS devices, supported OS versions, and cellular connections used in its primary markets.
How to Measure Environment Coverage
Suppose a team defines 16 priority device, OS, browser, and network combinations.
If tests have been executed on 12 of these combinations:
Environment Coverage = (12 ÷ 16) × 100 = 75%
This measures coverage of the selected matrix, not every configuration that exists.
A useful environment coverage report should also show which combinations were tested, their execution results, and which important configurations remain untested.
How HeadSpin Supports Device and Environment Testing
HeadSpin provides real-device testing infrastructure for validating mobile and web applications across supported devices, browsers, and network conditions.
Teams can use HeadSpin's Appium and Selenium testing capabilities to execute existing automated tests on real devices and browsers. This helps teams extend testing to relevant device and network configurations.
HeadSpin supports this aspect of application testing, while code coverage measurement and requirements traceability remain separate parts of the overall coverage strategy.
What Is a Good Test Coverage Percentage?
There is no universally correct test coverage percentage.
A suitable target depends on the application's complexity, business requirements, risk level, and the type of coverage being measured.
For example, a payment processing service may require more extensive testing of calculations, failures, and boundary conditions than a simple informational page.
Similarly, a team measuring branch coverage may use a different target from a team measuring requirements coverage.
Why 100% Coverage Is Not Always the Goal
Achieving 100% statement coverage means all applicable executable statements were exercised during the measured tests.
It does not mean every possible input, condition, or expected behavior was tested.
A test suite can execute every line of code but still fail to detect incorrect calculations, missing validations, or problems involving external services.
The same limitation applies to requirements coverage. Having a test case mapped to every requirement does not necessarily mean that each requirement has been adequately verified.
How to Set Meaningful Coverage Targets
Teams should consider:
- Business criticality: Which features would have the greatest impact if they failed?
- Technical complexity: Which modules contain conditional logic, calculations, or difficult integrations?
- Change frequency: Which areas are frequently modified and may require stronger regression coverage?
- Historical defects: Which components have experienced repeated failures?
- Testing cost: Where would additional testing provide meaningful risk reduction?
A team might establish a minimum threshold for new-code coverage while requiring more thorough validation of high-risk workflows.
The important thing is to define the target, explain why it was chosen, and review whether the tests actually address the intended risks.
Popular Test Coverage Tools
Different test coverage tools serve different purposes. Some measure code execution, while others help teams review coverage reports, manage requirements, or evaluate test effectiveness.
Choosing the right tool depends on the programming language, testing framework, and type of coverage required.
Code Coverage Measurement Tools
For example, JaCoCo is useful for identifying uncovered branches in Java applications, while Coverage.py helps Python developers identify missing statement and branch execution.
Coverage Reporting and Test Management Tools
These tools should not be confused with code coverage collectors.
For example, SonarQube does not generally generate code coverage reports itself. It imports reports produced by compatible tools and makes the results available as part of code analysis.
Mutation Testing Tools
Mutation testing tools help determine whether existing tests can detect deliberate changes in code behavior.
How to choose: Use a code coverage tool to identify unexecuted code, test management tools to track coverage against requirements, and mutation testing tools when you need a deeper assessment of test effectiveness.
How to Improve Test Coverage
Improving test coverage starts with identifying meaningful gaps rather than simply increasing the number of automated tests.
1. Review Existing Coverage Gaps
Start with current coverage reports, requirements records, and test execution results.
Identify which requirements lack tests, which scenarios remain unexecuted, and which important code branches are uncovered.
Separate genuine gaps from intentionally excluded items so the team can focus on relevant work.
2. Prioritize High-Risk Functionality
Focus first on application areas where failure would have significant consequences.
For an e-commerce application, this might include payment authorization, order totals, refunds, and inventory updates.
Lower-risk functionality can be addressed according to its importance and the available testing resources.
3. Add Negative and Boundary Test Cases
Positive tests confirm that an application works when users provide expected inputs.
Negative and boundary tests check what happens when inputs are invalid, incomplete, or near allowed limits.
For example, a payment workflow should not be tested only with valid card details. Relevant scenarios may include declined transactions, expired cards, and interrupted payments.
4. Test Interactions Between Components
Unit tests are useful for checking isolated functions, but they may not expose problems involving multiple services.
Integration tests can help verify interactions between application components, while end-to-end tests validate complete workflows.
Choose the test level based on the behavior being verified rather than attempting to reproduce every unit test at the UI level.
5. Use Parameterized Tests Where Appropriate
Parameterized tests allow the same test logic to run with different input values.
For example, a login validation test may run with an empty password, an incorrect password, and a password containing unsupported characters.
Each input should represent a meaningful scenario. Adding large numbers of similar inputs without a clear purpose may increase execution time without significantly improving coverage.
6. Extend Testing to Relevant Environments
Review supported devices, operating systems, browsers, and networks.
Identify priority configurations that have not yet been tested, then add them to the execution plan.
Use actual application requirements and available usage data where possible to guide this selection.
7. Update Tests When Requirements Change
Coverage needs regular maintenance.
When developers introduce a feature or change existing behavior, review the affected requirements and test cases.
Remove obsolete scenarios, update expected results, and add tests for new behavior.
This helps ensure that coverage remains relevant as the application evolves.
Code Coverage Best Practices
Code coverage best practices focus on collecting reliable code execution measurements and using those measurements to strengthen automated tests.
1. Measure More Than Line Coverage
Line coverage provides a useful starting point, but it may not reveal missing decision outcomes.
Branch coverage can expose logic that executes differently depending on inputs or conditions.
For modules containing complex decisions, reviewing condition coverage or using mutation testing may provide additional insight.
2. Write Assertions That Verify Expected Results
A test should do more than call a function.
For example, a test for a tax calculation should verify the expected amount, including relevant rounding rules and boundary conditions.
Otherwise, the code may register as covered even when its output is incorrect.
3. Review Uncovered Code Before Adding Tests
Not every uncovered line represents the same level of risk.
Inspect the uncovered code to understand its purpose and determine whether it requires an additional test.
Pay particular attention to error handling, conditional logic, and recently modified business rules.
4. Configure Coverage Exclusions Carefully
Coverage tools often allow teams to exclude specific files or code sections from measurement.
Exclusions may be appropriate for some generated code or files outside the intended measurement scope.
However, excluding difficult-to-test application logic simply to increase the coverage percentage makes the resulting metric less useful.
Document exclusions and review them when the project changes.
5. Track Coverage for Newly Changed Code
A large existing codebase may contain coverage gaps accumulated over several years.
Measuring coverage for newly added or modified code helps teams identify whether recent changes introduce further gaps.
Maintain visibility into overall coverage as well, particularly for older components that remain business-critical.
6. Keep Coverage Reports Comparable
Use consistent measurement settings when comparing coverage across builds.
Changes in instrumentation, file exclusions, test selection, or coverage tools can affect reported percentages.
A sudden change in coverage should be investigated before assuming that test quality has improved or declined.
Test Coverage in CI/CD
Continuous Integration and Continuous Delivery (CI/CD) pipelines allow teams to run automated tests regularly as developers introduce changes.
Integrating coverage collection into these pipelines helps identify testing gaps closer to the time changes are made.
How Coverage Fits into a CI/CD Pipeline
A typical workflow may include:
- Code changes are submitted. A developer opens or updates a pull request.
- The application is built. The pipeline prepares the application and test environment.
- Automated tests run. Selected unit and integration tests execute against the changes.
- Coverage data is collected. A compatible tool records which code structures were exercised.
- Reports are generated. Coverage results are published for developers and reviewers.
- Coverage changes are evaluated. The team examines new gaps, relevant thresholds, and test failures before merging or releasing.
For example, a pipeline might collect Java code coverage using JaCoCo and import the report into SonarQube.
SonarQube supports configurable quality gates, including conditions related to coverage on new code.
Should Low Coverage Automatically Fail a Build?
A coverage threshold can be useful when it reflects a deliberate engineering policy.
For instance, a team may configure its CI pipeline to flag a reduction in new-code coverage below an agreed minimum.
However, coverage alone should not determine whether a release is ready.
An application might satisfy its configured coverage threshold while still containing failing tests, unresolved defects, or untested business-critical scenarios.
Teams should evaluate coverage alongside test results, defect severity, and release-specific risks.
Keep Functional Coverage Visible Too
Code coverage reports do not replace records of functional testing.
For features that require browser, mobile, or end-to-end validation, teams should also track scenario execution and results.
Maintaining this distinction helps prevent a high code coverage score from being mistaken for complete application validation.
Common Test Coverage Anti-Patterns
Test coverage metrics become less useful when teams focus on improving reported numbers without addressing the quality of their tests.
The following practices can create misleading results.
Example: High Coverage, Weak Validation
Suppose an application contains a discount calculation function.
A test calls the function with a valid order amount but does not verify the calculated discount.
The coverage tool may report that the relevant statements were executed.
However, if a developer accidentally changes the discount from 10% to 20%, the test might still pass.
This is an example of why coverage should be used to identify testing gaps rather than treated as proof that the application is correct.
Requirements Traceability Matrix Template
A Requirements Traceability Matrix (RTM) connects application requirements to the tests intended to verify them.
It helps teams identify requirements without test cases, monitor test execution, and understand which requirements have not yet been successfully validated.
An RTM can be maintained in a spreadsheet or supported test management system.
Example Requirements Traceability Matrix
Consider an online shopping application with the following requirements.
This matrix contains hypothetical requirements and results for illustration.
How to Interpret the Matrix
The example contains five requirements.
Four requirements have corresponding test cases, giving a requirements mapping coverage of:
Requirements Coverage = (4 ÷ 5) × 100 = 80%
However, only three requirements have had their listed tests executed:
Requirements with Executed Tests = (3 ÷ 5) × 100 = 60%
Of those five requirements, two have listed tests that passed, one has a failing test, one has not been executed, and one has no assigned test.
These numbers describe different aspects of testing progress and should be reported separately.
How to Create Your Own RTM
Start by recording each requirement with a unique ID.
Then link the test cases that validate that requirement, including positive, negative, and boundary scenarios where relevant.
Update execution results whenever tests run, and review the matrix when requirements change.
A more detailed RTM can also include the requirement owner, priority, application version, defect IDs, execution date, and testing environment.
Important: A requirement having one mapped test does not automatically mean the requirement has been tested thoroughly. The mapping should be reviewed against its acceptance criteria and expected behavior.
Conclusion
Test coverage helps teams understand what they have tested and where important gaps remain. It can be measured across requirements, features, code, scenarios, and supported environments.
However, high coverage does not automatically mean an application is reliable. The quality of test cases, their assertions, execution results, and the risks they address all matter.
A useful test coverage strategy combines appropriate metrics with meaningful test design, regular coverage reviews, and testing across relevant application environments.
The goal is not simply to achieve a higher percentage. It is to identify the areas that need attention and use that information to make better testing decisions.
Originally Published: https://www.headspin.io/blog/what-is-test-coverage-comprehensive-guide









Top comments (0)