Rails makes error reporting tests easier in Rails 7.1

Introduction

Rails continues to refine its built-in error handling tools. Testing error reporting behavior has become more precise with new testing utilities introduced in Rails 7.1.

Rails 7.1 brought us assert_error_reported and assert_no_error_reported. These additions make our test suites more expressive and align better with Rails testing conventions.

Rails 8.1 takes this further with capture_error_reports. This latest addition gives us even more control when we need to verify error details like messages and context.

Before

Before this change, verifying that an error was reported through Rails.error.report was not straightforward.

We often relied on mocks or indirect test expectations. This approach ensured that our code handled errors properly.

# Old approach using mocks
expect(Rails.error).to receive(:report).with(instance_of(MyCustomError))
MyService.call

While this worked, it had drawbacks. It tightly coupled our tests to internal Rails APIs. This made tests harder to maintain over time.

After

With the latest Rails improvements, we can use built-in assertions. We can now check whether an error has been reported without relying on mocks.

# New approach with built-in assertions
def test_error_reporting
  assert_error_reported(MyCustomError) do
    MyService.call
  end
end

def test_no_error_reporting
  assert_no_error_reported do
    SafeService.call
  end
end

These assertions automatically track calls to Rails.error.report. They work within the provided block and ensure our expectations are met. This helps us write cleaner, more reliable tests.

How It Works

These assertions work seamlessly with Rails.error. They integrate with ActiveSupport::Testing::Assertions.

Matching specific errors: We can match specific error classes or conditions.

Clear failure messages: The assertions provide clear failure messages. This happens when an error is reported (or not reported) unexpectedly.

Declarative test cases: They encourage us to write more declarative and readable test cases.

By using these new assertions, we improve our test suites. Both readability and confidence increase significantly.

Capturing Error Reports for Detailed Verification

Sometimes we need more than just asserting that an error was reported. We might want to verify error messages, context, or other metadata.

Rails 8.1 introduces capture_error_reports for these scenarios. This method captures all errors reported within a block and returns them as an array. It’s a natural evolution of the error reporting test utilities that started in Rails 7.1.

def test_error_details
  reports = capture_error_reports do
    Rails.error.report(IOError.new("Something went wrong"), context: { user_id: 123 })
  end

  assert_equal 1, reports.size
  assert_equal "Something went wrong", reports.first.error.message
  assert_equal 123, reports.first.context[:user_id]
end

This is particularly useful when we need to:

Verify error messages: Check that the right error message is being reported.

Inspect error context: Ensure proper context data is attached to error reports.

Filter specific error types: Capture only errors of a specific class while ignoring others.

def test_filtered_errors
  reports = capture_error_reports(IOError) do
    Rails.error.report(IOError.new("Oops"))
    Rails.error.report(IOError.new("Oh no"))
    Rails.error.report(StandardError.new)
  end

  assert_equal 2, reports.size
  assert_equal "Oops", reports.first.error.message
  assert_equal "Oh no", reports.last.error.message
end

The capture_error_reports method gives us fine-grained control over our error reporting tests. It complements the assertion methods perfectly.

Why This Matters

Error handling is an essential part of any robust Rails application. These new assertions make it easier to ensure errors are captured and reported consistently.

Benefits:

They reduce boilerplate code in our tests.

They eliminate the need for mocking Rails internals.

They make our test suite’s intent much clearer.

This aligns perfectly with Rails’ philosophy of convention over configuration. Rails continues to provide expressive and intuitive APIs for common needs.

Quick references

Need help on your Ruby on Rails or React project?

Join Our Newsletter