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_logfunction: 
log = capture_log(fn ->
  # Code that generates logs
end)
- The 
capture_logfunction: 
- 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!
Further Reading
TIL - Capturing logs in Elixir tests
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....