DEV Community

David Wessman
David Wessman

Posted on • Edited on • Originally published at wessman.co

1 1

Rails: Minitest results output in TAP-format for Heroku CI

When using Heroku CI for automatic testing, the default output is just pass or fail without any parsing of how many tests passed or what errors where found.

This can be improved if you output the results in the Test Anything Protocol-format (TAP-format) according to Heroku.

This format is not built into the test frameworks used in Ruby on Rails. Therefore I had to write my own test reporter.

I chose to implement this for Minitest and decided to use the gem
minitest-reporters.

Expected outcome

I have a small project where the test suit looks like this:
Output of test results without formatting

To adhere to the TAP-format I need it to also output:

TAP version 13
1..7
ok 1 - AccountsControllerTest - test_renders_users_account
ok 2 - AccountsControllerTest - test_require_login
ok 3 - CallbacksMessagesControllerTest - test_handle_status_callback
ok 4 - MessagesControllerTest - test_should_create_message
ok 5 - ContactsControllerTest - test_should_create_contact
ok 6 - ContactsControllerTest - test_should_update_contact
ok 7 - ContactsControllerTest - test_show_contact
Enter fullscreen mode Exit fullscreen mode

Solution

I created a custom reporter called TapReporter by inspecting a standard reporter from the minitest-reporters gem called ProgressReporter (see source):

module Minitest
module Reporters
# Based on https://github.com/kern/minitest-reporters/blob/master/lib/minitest/reporters/progress_reporter.rb
# Tries to adhere to https://testanything.org/tap-specification.html
class TapReporter < DefaultReporter
def report
super
puts("TAP version 13")
puts("1..#{tests.length}")
tests.each_with_index do |test, index|
test_str = "#{test_class(test)} - #{test.name.tr("#", "_")}"
if test.passed?
puts "ok #{index + 1} - #{test_str}"
elsif test.skipped?
puts "ok #{index + 1} # skip: #{test_str}"
elsif test.failure.present?
puts "not ok #{index + 1} - failed: #{test_str}"
message_for(test).each_line do |line|
print_padded_comment(line)
end
unless test.failure.is_a?(MiniTest::UnexpectedError)
trace = filter_backtrace(test.failure.backtrace)
trace.each do |line|
print_padded_comment(line)
end
end
puts
end
end
end
private
def print_padded_comment(line)
puts "##{pad(line)}"
end
end
end
end
view raw tap_reporter.rb hosted with ❤ by GitHub

Output of test results with TAP-formatting

The solution on Heroku

A failing test

A failing test on Heroku

Successful tests

Successful tests on Heroku

Keywords

Image of Stellar post

How a Hackathon Win Led to My Startup Getting Funded

In this episode, you'll see:

  • The hackathon wins that sparked the journey.
  • The moment José and Joseph decided to go all-in.
  • Building a working prototype on Stellar.
  • Using the PassKeys feature of Soroban.
  • Getting funded via the Stellar Community Fund.

Watch the video 🎥

Top comments (0)

Jetbrains image

Build Secure, Ship Fast

Discover best practices to secure CI/CD without slowing down your pipeline.

Read more

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay