Testing logging can be tricky but recently I’ve learned that Elixir’s ExUnit ships with a CaptureLog
module that makes it easy to test logging behavior. I was really happy to see this built-in!
Let’s say you have a function that processes a template and logs errors when something goes wrong. You want to test both the error handling and ensure the right messages are being logged. Here’s a simplified version of such a function:
def render_template(%SourceFile{is_template: true} = source_file, vars) do
case Solid.parse(source_file.content) do
{:ok, template} ->
# Template parsing succeeded, render it...
{:error, reason} ->
Logger.error("Template parsing failed", reason: reason)
{:error, :template_parsing_failed}
end
end
Without ExUnit.CaptureLog
, testing this would result in error messages cluttering your test output, even though those errors are expected as part of the test.
ExUnit.CaptureLog
allows you to:
- Capture log messages during test execution
- Assert against the content of those messages
- Keep your test output clean by suppressing expected error logs
Here’s how I used it:
defmodule YourTest do
use ExUnit.Case
import ExUnit.CaptureLog
test "handles invalid template syntax" do
file = %SourceFile{
content: "{{ unclosed tag",
is_template: true
}
# Capture logs during template rendering
log = capture_log(fn ->
assert {:error, "Template parsing failed: " <> _} =
render_template(file, %{})
end)
# Assert against the captured log content
assert log =~ "Template parsing failed"
assert log =~ "expected end of string"
assert log =~ "{{ unclosed tag"
end
end
Breaking Down the Test
Let’s see what’s happening:
- First, we import the helper function:
import ExUnit.CaptureLog
- We wrap the code that generates logs in a
capture_log
function:
log = capture_log(fn ->
# Code that generates logs
end)
- The
capture_log
function:
- Takes a function as an argument
- Executes that function
- Captures any log output during execution
- Returns the captured log as a string
- We can then make assertions about the log content using string matching:
assert log =~ "Template parsing failed"
Benefits
Using CaptureLog
provides several advantages:
Clean Test Output: Error logs don’t pollute your test output, making it easier to spot real test failures.
Explicit Verification: You can verify that your error handling is not just returning the right values, but also logging the right information.
Better Documentation: The test clearly shows what log messages are expected when errors occur.
ExUnit.CaptureLog
is a great tool for testing logging behavior in your Elixir applications. It helps you write more comprehensive tests while keeping your test output clean. Next time you need to test code that generates logs, remember that you can capture and verify those logs as part of your test assertions.
Today I learned!