MiniTest Events


A few weeks ago I made a hack to MiniTest to add Fuubar-like functionality. Unfortunately the hack was a little dirty, and I wanted to make MiniTest more extendable, at least for reporting purposes. My solution was to borrow from the Events system I wrote for Harbor (a web framework we wrote and use at Wieck Media).

The concept is very simple; you just raise an event wherever you feel you need to, and pass in a context object of some kind. Then you register an event handler, which is just a class with a call method that is executed at the time of the event raise.

For example, here I am raising an event just before all of the tests begin to run:

  event = RunAnythingEvent.new(self, type, suites, options)
  
  raise_event(:run_anything_start, event)

As you can see it’s using a special RunAnythingEvent context object, whose definition looks like so:

  class RunAnythingEvent < BaseEvent
    
    attr_reader :runner, :type, :output, :suites, :options
    attr_accessor :test_count, :assertion_count, :report, :failures, :errors, :skips
    
    def initialize(runner, type, suites, options)
      super()
      @runner = runner
      @output = runner.output
      @suites = suites
      @type = type
      @options = options
    end
    
  end

And here is an example of an event handler for this event:

  class RunAnythingStartHandler
  
    def initialize(event)
      @event = event
      @output = event.output
      @type = event.type
    end
  
    def call
      @output.puts
      @output.puts "# Running #{@type}s:"
      @output.puts
    end
  
  end

Which is registered by calling the following method off the class where the event was raised:

  register_event_handler(:run_anything_start, RunAnythingStartHandler)

This particular example illustrates an important part of my goal. I wanted to decouple the reporting of the tests from the actual tests themselves. In order to further this I have created plugins that enable and disable the required event handlers which deal with outputting results in specific ways. I have also moved all the base reporting into a plugin (MiniTest::Reporting) which is enabled by default.

The next step, which I’ve already partially completed, is to create plugins that handle alternative output options like the progress bar and instafailing. If you’re interested, the work is being done in the events branch on my Github account. Assuming Node.js doesn’t monopolize all my time, I hope to have it completed in the near future. If you have any ideas, feel free to let me know.

subscribe! reddit! hacker news!

blog comments powered by Disqus
Fork me on GitHub