Advanced 25 min read

Code Coverage vs Meaningful Testing

By the end of this lesson, you'll be able to:

  • Recognize a test written purely to hit a coverage number without verifying behavior
  • Explain why 100% coverage doesn't guarantee correctness
  • Apply this module's full toolkit to write tests that are both high-coverage and meaningful

Prerequisites: "Mocking HTTP Callouts"

A test that hits 100% coverage and verifies nothing

@isTest
static void testCalculateAndFormat() {
    Calculator calc = new Calculator();
    calc.calculateAndFormat(12, 5, '+'); // runs every line... but asserts nothing at all!
}
  1. @isTest — marks the test method.
  2. static void testCalculateAndFormat() { — this test genuinely executes every line inside calculateAndFormat, contributing real percentage points to the org's code coverage.
  3. Calculator calc = new Calculator(); — creates the calculator.
  4. calc.calculateAndFormat(12, 5, '+'); — runs it, but asserts nothing at all — it would pass even if the method were completely broken, because it never checks the result. This is exactly Lesson 1's warning, made concrete: coverage counts lines executed, not correctness verified.
  5. } — closes the test method.

The same coverage, genuinely meaningful

@isTest
static void additionReturnsCorrectlyFormattedSum() {
    Calculator calc = new Calculator();
    String result = calc.calculateAndFormat(12, 5, '+');
    System.assertEquals('12 + 5 = 17.00', result); // Lesson 5's specific-value assertion
}

@isTest
static void divisionByZeroReturnsErrorMessage() {
    Calculator calc = new Calculator();
    String result = calc.calculateAndFormat(10, 0, '/');
    System.assertEquals('Error: cannot divide by zero.', result);
}
  1. @isTest — marks the first test method.
  2. static void additionReturnsCorrectlyFormattedSum() { — one scenario per test method (Lesson 2).
  3. Calculator calc = new Calculator(); — creates the calculator.
  4. String result = calc.calculateAndFormat(12, 5, '+'); — runs the same lines as the weak test above.
  5. System.assertEquals('12 + 5 = 17.00', result); — Lesson 5's specific-value assertion — now this scenario actually verifies a specific, correct outcome.
  6. } — closes this test method.
  7. (blank line)
  8. @isTest — marks a second test method.
  9. static void divisionByZeroReturnsErrorMessage() { — exception paths tested explicitly (Lesson 6).
  10. Calculator calc = new Calculator(); — creates the calculator.
  11. String result = calc.calculateAndFormat(10, 0, '/'); — the division-by-zero scenario.
  12. System.assertEquals('Error: cannot divide by zero.', result); — asserts the specific expected error message.
  13. } — closes this test method.

Same lines of Calculator covered as the weak test — but now every scenario actually verifies a specific, correct outcome. This is the whole module's toolkit converging.

A checklist for meaningful tests going forward

  • Does every test method assert a specific expected value, not just "no exception" or "not null"? (Lesson 5)
  • Are both the happy path and the exception/edge-case paths covered? (Lesson 6)
  • Is there at least one bulk test (200 records) for every trigger? (Lesson 7)
  • Is repeated setup extracted into a factory, keeping each test focused on what it's actually verifying? (Lesson 8)

Coverage percentage tells you how much code ran during testing; this checklist is what actually tells you whether the tests are worth trusting.

Exercise

This test hits 100% coverage but verifies nothing. Rewrite it with a specific assertion.

Show hint

Add a System.assertEquals with the actual expected value.

APEX

Code Coverage vs Meaningful Testing Quiz

1. Can a test with 100% line coverage still fail to catch a real bug?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

This closing lesson returns to Lesson 1's opening warning with the full toolkit now in hand: coverage measures which lines ran, not whether the tests actually verify anything — and every technique in this module exists to close that gap.