BLOG.siposdani87

Create SonarQube report from Rails minitest

Create reporter class for SonarQube Generic Test Data export
By: Dániel Sipos on

Rails makes it super easy to write tests. It starts by producing skeleton test code while you are creating your models and controllers. Rails default test framework is Minitest.

SonarQube supports generic formats for test coverage and test execution import. The native output of Minitest coverage tool is not supported by SonarQube, so must convert it to Generic Test Data format.

Minitest-reporters gem will swap out the Minitest runner to the custom one used by minitest-reporters and use the correct reporters for Textmate, Rubymine, and the console. This gem is great, but does not include reporter for SonarQube. So I wrote own reporter, just include Minitest::Reporter and I override the methods.

Create sonar_qube_reporter.rb in your lib directory:

require 'minitest/reporters'

# A reporter for writing SonarQube test reports (Generic Test Data)
class SonarQubeReporter < Minitest::Reporters::JUnitReporter
  def report
    puts "Writing XML reports to #{@reports_path}"
    suites = tests.group_by do |test|
      test_class(test)
    end

    if @single_file
      xml = Builder::XmlMarkup.new(:indent => 2)
      xml.instruct!
      xml.testExecutions(:version => 1) do
        suites.each do |suite, tests|
          parse_xml_for(xml, suite, tests)
        end
      end
      File.open(filename_for('minitest'), 'w') { |file| file << xml.target! }
    else
      suites.each do |suite, tests|
        xml = Builder::XmlMarkup.new(:indent => 2)
        xml.instruct!
        xml.testExecutions(:version => 1) do
          parse_xml_for(xml, suite, tests)
        end
        File.open(filename_for(suite), 'w') { |file| file << xml.target! }
      end
    end
  end

  private

  def parse_xml_for(xml, _suite, tests)
    file_path = get_relative_path(tests.first)

    xml.file(:path => file_path) do
      tests.each do |test|
        xml.testCase(:name => test.name, :duration => (test.time * 1000).to_i) do
          xml << xml_message_for(test) unless test.passed?
        end
      end
    end
  end
end

Use the previously defined class in your test/test_helper.rb file, such as the following example.

require 'minitest/reporters'
require 'sonar_qube_reporter'

Minitest::Reporters.use! [Minitest::Reporters::ProgressReporter.new, SonarQubeReporter.new('test/reports', true, { single_file: true })] unless ENV.fetch('RM_INFO', false)

Finally, the following properties must be set in the project file sonar-project.properties to be processed.

sonar.testExecutionReportPaths=test/reports/TEST-minitest.xml

Conclusion

A very clean and easy-to-use solution was created for the Minitest report problem.

Share with your friends

Related posts