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.
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!