0Pricing
Lua Academy · Lesson

Code Coverage and Test Instrumentation

Measure test coverage with luacov and interpret coverage reports.

Code Coverage and Test Instrumentation is a free Lua Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is Code Coverage?

Code coverage measures which lines, branches, or functions of your code are executed by tests. High coverage gives confidence that tests are exercising the code well.

luacov: The Standard Tool

luacov is the standard Lua coverage tool. It hooks into the Lua debug layer and records which lines are executed.

-- Run with luacov:
luacov script.lua
-- Or require at the start of the test file:
require("luacov")

Using luacov with a Test Runner

With busted or a custom runner, require luacov at the start and it automatically records coverage.

-- spec/all_spec.lua
require("luacov")
describe("my module", function()
  it("does something", function()
    local m = require("mymodule")
    assert.equals(m.add(1,2), 3)
  end)
end)

Generating a Report

After tests run, luacov writes a luacov.stats.out file. Run luacov-reporter to generate a human-readable report.

# After tests:
luacov-reporter
# Produces luacov.report.out with per-file line coverage

Reading the Report

Each line shows: hit count, miss count, and the source line. Lines with 0 hits are uncovered code — potential dead code or missing test cases.

Branch Coverage

luacov tracks line coverage, not branch coverage. For branch coverage, use a more advanced tool or add test cases for every if/else path manually.

Custom Coverage Hook

Build a minimal coverage recorder with debug.sethook for line events.

local covered = {}
debug.sethook(function(event, line)
  local info = debug.getinfo(2, "S")
  local src = info.short_src
  covered[src] = covered[src] or {}
  covered[src][line] = (covered[src][line] or 0) + 1
end, "l")
-- ... run tests ...
debug.sethook()

Coverage Thresholds

Set a minimum coverage threshold in CI (e.g., 80%). Fail the build if coverage drops below it. This prevents accidental dead code from accumulating.

Test Instrumentation Patterns

Beyond coverage, instrument tests with: execution time (detect slow tests), call count assertions (verify functions are called the expected number of times), and value capture (record arguments passed to mocked functions).

Mocking for Test Isolation

Replace real modules with mocks during testing to isolate units. Store the real function, replace with a tracking stub, restore after the test.

local realSend = http.send
local calls = {}
http.send = function(...) calls[#calls+1] = {...} end
-- run tests --
http.send = realSend  -- restore
print(#calls, "send calls")

Integration with CI

Run luacov in your CI pipeline. Upload coverage reports to Coveralls or Codecov for trend tracking across commits.

Coverage Question

What does a line with 0 hits in a luacov report indicate?

Recap: Code Coverage and Test Instrumentation

Use luacov to record line coverage and generate reports. Set CI coverage thresholds. Add custom debug.sethook instrumentation for specialized tracking. Use mocks for unit test isolation and call count verification.

Frequently asked questions

Is the “Code Coverage and Test Instrumentation” lesson free?

Yes — the full text of “Code Coverage and Test Instrumentation” is free to read here on the web, and the Lua Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Lua Academy course, upgrade to CoddyKit PRO.

What will I learn in “Code Coverage and Test Instrumentation”?

Measure test coverage with luacov and interpret coverage reports. You practise Lua Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Lua Academy?

No prior experience is required. Lua Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Code Coverage and Test Instrumentation” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Lua Academy lesson?

Yes. Every Lua Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The debug Library in Depth
  2. Remote Debugging with MobDebug
  3. Profiling with LuaProfiler
  4. Code Coverage and Test Instrumentation
← Back to Lua Academy