Code Reading: RSpec Output Formatting

As I mentioned in my post on "shared examples", each example group generated by RSpec is passed a reporter object when it's run. Reporters notify listeners of events like #example_group_started or #example_failed. Listeners can then print output based on these events.

That's the gist of how output formatting in RSpec works; this post examines it in slightly more detail.

Specifying a formatter on the command line

We can specify which formatter we'd like RSpec to use by providing the --format option on the command line, like so:

$ rspec --format p # => Uses RSpec::Core::Formatters::ProgressFormatter
$ rspec # => Uses the default (RSpec::Core::Formatters::ProgressFormatter)
$ rspec --format j # => Uses RSpec::Core::Formatters::JsonFormatter
$ rspec --format MyCustomFormatter # => Uses MyCustomFormatter class. Attempts to require the file "my_custom_formatter.rb" if not loaded already.

When we execute rspec, an instance of RSpec::Core::CommandLine is initialized with the options passed via the command line. During the initialization, the formatter argument is added to a collection of formatters maintained by the RSpec.configuration singleton. The singleton is also initialized with a reporter, an instance of RSpec::Core::Reporter. Each formatter is registered as a listener of the reporter.

Notifying formatters of events

The spec files are then loaded and their example groups are run. Each example group is passed a reference to the reporter singleton when executed. Example groups and their examples notify the reporter whenever they begin, end, fail, etc.

Examples and example groups notify the reporter as they run.

The reporter passes these messages along to its listeners: the formatters specified in the previous section. The formatters then determine what to output; whether that be text, JSON, or some other representation.


Simple, right? RSpec makes it seem deceptively so because of how well it's architected. In a future post, I'll cover Kiwi's implementation of reporting. Stay tuned!

More on RSpec