Code Coverage: Guide to Metrics & Improving Coverage

Lasse R.Lasse R.
11 min read

Code coverage measures how much of your code is tested. Here's what you need to know:

  • It's calculated as: (Lines executed / Total lines) * 100

  • Higher coverage can lead to better quality and fewer bugs

  • But 100% coverage isn't always necessary or practical

Key coverage metrics:

MetricMeasures
StatementCode lines run
BranchDecision paths taken
FunctionFunctions called
ConditionBoolean expressions tested

To improve coverage:

  • Write good unit tests

  • Use test-driven development

  • Focus on critical code paths

  • Test edge cases and errors

  • Make code easier to test

Remember: High coverage doesn't guarantee bug-free code. Focus on writing meaningful tests that verify functionality, not just boosting numbers.

Basics of Code Coverage

Code coverage is a tool that shows how much of your code your tests are checking. It's like a map that highlights the parts of your code that need more testing.

What Code Coverage Measures

Code coverage looks at:

  • Lines of code your tests run

  • Functions your tests use

  • Paths through your code

  • Different outcomes your tests check

Think of it like this:

Code Coverage = (Tested code / Total code) * 100

Types of Code Coverage

Here are the main types:

TypeMeasures
StatementCode statements run
BranchCode branches taken
FunctionFunctions called
ConditionBoolean conditions tested

Limits of Code Coverage

Code coverage is useful, but it's not perfect:

1. High coverage doesn't mean no bugs

2. Good tests matter more than lots of tests

3. It can miss some problems

4. It might lead to bad testing habits

As Sten Pittet from Atlassian says:

"Good coverage does not equal good tests."

Main Code Coverage Metrics

Code coverage metrics show how much of your code gets tested. Here are the key ones:

Statement Coverage

This measures the percentage of code lines your tests run. It's simple but misses some details.

def greet(name):
    if name:
        print(f"Hello, {name}!")
    else:
        print("Hello, stranger!")

Testing with just a name? You'd hit 66% coverage (2 out of 3 lines).

Branch Coverage

Branch coverage looks at decision points in your code. It's more thorough than statement coverage.

Using the same example:

def greet(name):
    if name:  # This is a branch
        print(f"Hello, {name}!")
    else:
        print("Hello, stranger!")

For 100% branch coverage, test with and without a name.

Function Coverage

This tracks which functions your tests call. Great for finding dead code.

MetricMeasuresGoodBad
StatementExecuted linesEasy to getMisses paths
BranchDecision pointsMore detailedCan get complex
FunctionCalled functionsSpots unused codeMisses internal details

Condition Coverage

This checks all outcomes of boolean expressions. It's more granular than branch coverage.

Example:

def check_eligibility(age, income):
    if age > 18 and income > 30000:
        return "Eligible"
    return "Not eligible"

For full condition coverage, test:

  • age > 18 (true/false)

  • income > 30000 (true/false)

  • All combos of these

MC/DC Coverage

Modified Condition/Decision Coverage is a high-level metric for critical systems. It ensures each condition independently affects the outcome.

MC/DC needs:

  1. Every condition takes all outcomes

  2. Every decision takes all outcomes

  3. Each condition independently affects the decision

It's complex and mainly used in high-stakes software like aviation systems.

Tools for Code Coverage

Let's dive into some popular code coverage tools and what they offer.

Common Code Coverage Tools

Here's a quick look at widely-used tools:

ToolLanguage SupportKey Features
JaCoCoJavaMeasures line, branch, and instruction coverage
CoberturaJava, JavaScript, RubyEasy-to-read reports, tracks historical data
IstanbulJavaScriptTracks statements, lines, branches, and functions
SonarQubeMultiple languagesPlays nice with other tools, manages code quality
XcodeSwift, Objective-CBuilt-in coverage for Apple platforms

What to Look For

When picking a code coverage tool, keep an eye out for:

  • Clear, actionable reports

  • Smooth integration with your workflow

  • Support for various coverage metrics

  • Visual data representation

Plugging Tools into CI/CD

Want to keep your code quality high? Here's how to use these tools in your CI/CD pipeline:

1. Automate: Set up automatic coverage tests for each commit.

2. Set minimums: Define a coverage threshold. If you fall short, fail the build.

3. Watch trends: Keep tabs on coverage over time.

4. Share results: Auto-generate and distribute coverage reports to your team.

Reading Code Coverage Reports

Code coverage reports show how well your tests check your code. Here's how to understand them:

Report Sections

A typical report includes:

SectionWhat It Means
Overall CoverageTotal code tested
Statement CoverageIndividual statements run
Branch CoverageDecision paths taken
Function CoverageFunctions called
Line CoverageExecutable lines run

Each part tells you something different about your tests.

Spotting Low Coverage

To find poorly tested areas:

  1. Look for red or yellow highlights

  2. Check for low percentages in modules or classes

  3. Watch for complex functions with low branch coverage

For instance, a Jest report for a React app showed 84% coverage for statements and lines, but 100% for branches and functions. This means statement and line coverage could be better.

Where to Improve

When deciding what to test more:

  • Focus on critical code first

  • Target complex areas

  • Test recent changes thoroughly

Tools like SonarQube can help you find untested code by letting you explore specific parts of your project.

sbb-itb-0e28928

Ways to Improve Code Coverage

Want better code coverage? Here's how:

Writing Good Unit Tests

Make your unit tests rock:

  • Use AAA: Arrange, Act, Assert

  • Keep tests consistent

  • One scenario per test

  • Automate everything

Using Test-Driven Development (TDD)

TDD boosts coverage. Here's the cycle:

1. Write a failing test

2. Code to pass the test

3. Refactor (keep tests passing)

Result? Better design, more coverage.

Testing Important Code Paths

Focus on what matters:

  • High-traffic code

  • Core functionality

  • User-facing features

Testing Edge Cases and Errors

Don't forget the weird stuff:

  • Boundary conditions

  • Error handling

  • Use mocking for different scenarios

Making Code Easier to Test

Tweak your code:

  • Break down complex functions

  • Use dependency injection

  • Separate concerns

Practical Tips for Improving Coverage

TipHow-To
Set goalsAim for 70-80% with TDD
Track changesUse CI, compare builds
Use milestonesSchedule coverage reviews
New code focus80% coverage on fresh code
Smart toolsTry Pitest (Java) or Stryker Mutator (JavaScript)

Remember: High coverage ≠ quality. Ann from SonarSource says:

"Ignore overall coverage and enforce that all New Code has 80% coverage. Gradually... overall coverage will naturally increase."

Code Coverage Best Practices

Set Achievable Goals

Don't chase 100% coverage. It's often a waste of time and resources. Instead:

  • Google's guidelines: 60% (acceptable), 75% (commendable), 90% (exemplary)

  • Many open-source projects on OtterWise: ~80% coverage

Start small: If you're at 17.5%, aim for 19.5% next.

Balance Speed and Quality

Focus on new code:

1. High patch check: New code should hit 80% coverage.

2. Project status target: Use OtterWise’s auto setting to push overall coverage up.

3. Critical files first: Use Codecov's Impact Analysis to find key production code.

Don't Test Just for Numbers

Tests should verify functionality, not just boost coverage. Try:

  • Starting QA during spec phase

  • Examining uncovered code for different testing approaches

"Clean as You Code... ignore overall coverage and enforce that all New Code has 80% coverage. Gradually... overall coverage will naturally increase." - Ann, SonarSource

Keep Improving

Make coverage a habit:

ActionWhy It Matters
Regular reviewsStay current
Sort by file % in CodecovTarget weak spots
Enforce quality gatesMaintain standards
Monitor trendsTrack progress

Remember: High coverage doesn't equal quality. Write tests that give real insights.

Common Code Coverage Challenges

Boosting code coverage isn't always easy. Here are some common hurdles and how to jump over them:

Old Code Headaches

Got a legacy system? You're probably staring at a mountain of untested code. It's like trying to renovate a house without knowing what's behind the walls.

Here's how to tackle it:

  • New code, new rules: Make sure all fresh code comes with tests. No exceptions.

  • Pick your battles: Can't test it all? Focus on the code that keeps your business running.

  • Slow and steady: Break down big, messy code chunks into smaller, testable pieces. Rome wasn't built in a day.

Time and People Crunch

Small team? Tight deadlines? It's tough to juggle new features and better coverage.

Try this:

  • Baby steps: If you're at 20% coverage, aim for 25%. Don't shoot for the moon right away.

  • Smart targeting: Use tools like Codecov's Impact Analysis to find the code that really matters.

  • Test as you go: Make testing part of your coding routine, not a chore you do later.

Tangled Code Webs

Big projects with lots of moving parts? Testing can feel like untangling Christmas lights.

Here's the game plan:

  • Fake it (temporarily): Use mocking frameworks to test components in isolation.

  • Divide and conquer: Create smaller, focused tests instead of trying to test everything at once.

  • Real-world checks: Set up end-to-end tests to catch issues that slip through the cracks.

When Reports Lie

Inaccurate coverage reports are like a broken compass. They'll lead you astray.

Fix it:

  • Stay current: Keep your coverage tools up-to-date to avoid known bugs.

  • Check your setup: Make sure your tools are configured correctly for your project.

  • Trust, but verify: Occasionally compare the actual code to the coverage report. Catch those sneaky errors.

Advanced Code Coverage Techniques

Let's look at some powerful ways to boost your code coverage:

Mutation Testing

Mutation testing takes your coverage up a notch. It tweaks your code and checks if your tests catch these changes.

Here's the process:

  1. Your code gets small changes (mutations)

  2. All tests run on this changed code

  3. If tests fail, good! They caught the mutation

  4. If tests pass, you might need better tests

Stryker, a big name in mutation testing, says teams using their tool saw a 15% bump in test effectiveness.

Property-Based Testing

Instead of specific test cases, property-based testing looks at rules your code should always follow.

For example:

  • A sorting function should always give an ordered list

  • A user creation function should always return a valid user object

The testing tool then makes tons of test cases to check these rules.

Automated Test Creation

AI is shaking things up in test creation. Tools like ACCELQ are pushing the limits.

FeatureBenefit
AI-powered test generationMakes tests 7.5x faster than manual methods
Self-healing capabilitiesCuts test maintenance by 72%
Codeless platformLets non-coders create complex tests

ACCELQ's CEO, Mahendra Alladi, says: "Our AI approach has helped big companies like Salesforce and Micron Technology slash testing costs by over 50%."

Conclusion

Code coverage is a handy tool, but it's not perfect. Here's what you need to know:

  • Different coverage types tell you different things

  • Mutation testing tools like Pitest and Stryker Mutator can help

  • Focus on new code coverage to improve overall quality

  • Don't chase 100% coverage - balance is key

Finding the Sweet Spot

Balancing coverage and development isn't easy. Here's how to do it:

1. Set realistic goals

Google suggests these coverage levels:

CoverageWhat it means
60%OK
75%Good
90%Great

Most teams see coverage drop after 80%.

2. Focus on what matters

Test critical code paths well, not every single line.

3. Clean as you code

Aim for 80% coverage on new code. It'll boost overall coverage over time.

4. Use mutation testing

It catches fake coverage and makes sure your tests actually work.

5. Use quality gates

Track progress by meeting quality requirements, not just looking at old coverage numbers.

Remember: Better software is the goal, not just higher numbers. As Ann from SonarSource says:

"Ignore overall coverage and enforce that all New Code has 80% coverage. Gradually - and this was our own experience internally - overall coverage will naturally increase."

FAQs

What is code coverage in QA testing?

Code coverage shows how much of your code gets tested. It's like a report card for your test suite.

Here's the deal:

If you have 100 lines of code and your tests run 80 of them, you've got 80% coverage.

Code coverage tools are sneaky. They add special instructions to your code to track what gets used during testing. This helps you spot the parts of your code that are flying under the radar.

What are coverage metrics?

Coverage metrics are different ways to measure how well your tests poke and prod your code. They help you find weak spots in your testing. Here are the main ones:

MetricWhat it looks at
Statement coverageHow many lines of code get run
Branch coverageHow many decision points (like if/else) get tested
Function coverageHow many functions get called
Condition coverageHow many true/false expressions get checked

Each metric gives you a different angle on your testing game.

But here's the kicker: High coverage doesn't mean your code is bulletproof. You need to write tests that really put your code through its paces, including those tricky edge cases.

0
Subscribe to my newsletter

Read articles from Lasse R. directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Lasse R.
Lasse R.