Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request ci-reporter#49 from realmyst/master
ci_reporter for MiniTest::Unit
  • Loading branch information
nicksieger committed Jan 28, 2012
2 parents c423e61 + a9d62ea commit cb87ca0
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 16 deletions.
2 changes: 2 additions & 0 deletions README.rdoc
Expand Up @@ -16,6 +16,7 @@ CI::Reporter works best with projects that use a +Rakefile+ along with the stand
require 'ci/reporter/rake/rspec' # use this if you're using RSpec
require 'ci/reporter/rake/cucumber' # use this if you're using Cucumber
require 'ci/reporter/rake/test_unit' # use this if you're using Test::Unit
require 'ci/reporter/rake/minitest' # use this if you're using MiniTest::Unit

2. Next, either modify your Rakefile to make the <code>ci:setup:rspec</code>, <code>ci:setup:cucumber</code> or <code>ci:setup:testunit</code> task a dependency of your test tasks, or include them on the Rake command-line before the name of the task that runs the tests or specs.

Expand All @@ -28,6 +29,7 @@ Report files are written, by default, to the <code>test/reports</code>, <code>fe
If you don't have control over the Rakefile or don't want to modify it, CI::Reporter has a substitute rake file that you can specify on the command-line. It assumes that the main project rake file is called +Rakefile+ and lives in the current directory. Run like so:

rake -f GEM_PATH/stub.rake ci:setup:testunit test
rake -f GEM_PATH/stub.rake ci:setup:minitest test
rake -f GEM_PATH/stub.rake ci:setup:rspec spec
rake -f GEM_PATH/stub.rake ci:setup:cucumber features

Expand Down
1 change: 1 addition & 0 deletions Rakefile
Expand Up @@ -100,6 +100,7 @@ task :generate_output do
begin
result_proc = proc {|ok,*| puts "Failures above are expected." unless ok }
ruby "-Ilib #{opts} -rci/reporter/rake/test_unit_loader acceptance/test_unit_example_test.rb", &result_proc
ruby "-Ilib #{opts} -rci/reporter/rake/minitest_loader acceptance/minitest_example_test.rb", &result_proc
ruby "-Ilib #{opts} -S #{@spec_bin} --require ci/reporter/rake/rspec_loader --format CI::Reporter::RSpec acceptance/rspec_example_spec.rb", &result_proc
ruby "-Ilib #{opts} -rci/reporter/rake/cucumber_loader -S cucumber --format CI::Reporter::Cucumber acceptance/cucumber", &result_proc
ensure
Expand Down
17 changes: 17 additions & 0 deletions acceptance/minitest_example_test.rb
@@ -0,0 +1,17 @@
require 'minitest/autorun'

class MiniTestExampleTestOne < MiniTest::Unit::TestCase
def test_one
puts "Some <![CDATA[on stdout]]>"
assert false
end
def teardown
raise "second failure"
end
end

class MiniTestExampleTestTwo < MiniTest::Unit::TestCase
def test_two
assert true
end
end
35 changes: 35 additions & 0 deletions acceptance/verification_spec.rb
Expand Up @@ -43,6 +43,41 @@
end
end

describe "MiniTest::Unit acceptance" do
it "should generate two XML files" do
File.exist?(File.join(REPORTS_DIR, 'TEST-MiniTestExampleTestOne.xml')).should == true
File.exist?(File.join(REPORTS_DIR, 'TEST-MiniTestExampleTestTwo.xml')).should == true
end

it "should have one error and one failure for MiniTestExampleTestOne" do
doc = File.open(File.join(REPORTS_DIR, 'TEST-MiniTestExampleTestOne.xml')) do |f|
REXML::Document.new(f)
end
doc.root.attributes["errors"].should == "1"
doc.root.attributes["failures"].should == "1"
doc.root.attributes["assertions"].should == "1"
doc.root.attributes["tests"].should == "1"
doc.root.elements.to_a("/testsuite/testcase").size.should == 1
doc.root.elements.to_a("/testsuite/testcase/error").size.should == 1
doc.root.elements.to_a("/testsuite/testcase/failure").size.should == 1
doc.root.elements.to_a("/testsuite/system-out").first.texts.inject("") do |c,e|
c << e.value; c
end.strip.should == "Some <![CDATA[on stdout]]>"
end

it "should have no errors or failures for MiniTestExampleTestTwo" do
doc = File.open(File.join(REPORTS_DIR, 'TEST-MiniTestExampleTestTwo.xml')) do |f|
REXML::Document.new(f)
end
doc.root.attributes["errors"].should == "0"
doc.root.attributes["failures"].should == "0"
doc.root.attributes["assertions"].should == "1"
doc.root.attributes["tests"].should == "1"
doc.root.elements.to_a("/testsuite/testcase").size.should == 1
doc.root.elements.to_a("/testsuite/testcase/failure").size.should == 0
end
end

describe "RSpec acceptance" do
it "should generate two XML files" do
File.exist?(File.join(REPORTS_DIR, 'SPEC-RSpec-example.xml')).should == true
Expand Down
28 changes: 14 additions & 14 deletions ci_reporter.gemspec
@@ -1,23 +1,23 @@
# -*- encoding: utf-8 -*-

Gem::Specification.new do |s|
s.name = %q{ci_reporter}
s.name = "ci_reporter"
s.version = "1.6.9"

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = [%q{Nick Sieger}]
s.date = %q{2011-12-15}
s.description = %q{CI::Reporter is an add-on to Test::Unit, RSpec and Cucumber that allows you to generate XML reports of your test, spec and/or feature runs. The resulting files can be read by a continuous integration system that understands Ant's JUnit report XML format, thus allowing your CI system to track test/spec successes and failures.}
s.email = %q{nick@nicksieger.com}
s.extra_rdoc_files = [%q{History.txt}, %q{Manifest.txt}, %q{LICENSE.txt}, %q{README.rdoc}]
s.files = [%q{History.txt}, %q{Manifest.txt}, %q{README.rdoc}, %q{LICENSE.txt}, %q{Rakefile}, %q{stub.rake}, %q{lib/ci/reporter/core.rb}, %q{lib/ci/reporter/cucumber.rb}, %q{lib/ci/reporter/report_manager.rb}, %q{lib/ci/reporter/rspec.rb}, %q{lib/ci/reporter/test_suite.rb}, %q{lib/ci/reporter/test_unit.rb}, %q{lib/ci/reporter/version.rb}, %q{lib/ci/reporter/rake/cucumber.rb}, %q{lib/ci/reporter/rake/cucumber_loader.rb}, %q{lib/ci/reporter/rake/rspec.rb}, %q{lib/ci/reporter/rake/rspec_loader.rb}, %q{lib/ci/reporter/rake/test_unit.rb}, %q{lib/ci/reporter/rake/test_unit_loader.rb}, %q{lib/ci/reporter/rake/utils.rb}, %q{spec/spec_helper.rb}, %q{spec/ci/reporter/cucumber_spec.rb}, %q{spec/ci/reporter/output_capture_spec.rb}, %q{spec/ci/reporter/report_manager_spec.rb}, %q{spec/ci/reporter/rspec_spec.rb}, %q{spec/ci/reporter/test_suite_spec.rb}, %q{spec/ci/reporter/test_unit_spec.rb}, %q{spec/ci/reporter/rake/rake_tasks_spec.rb}, %q{tasks/ci_reporter.rake}]
s.homepage = %q{http://caldersphere.rubyforge.org/ci_reporter}
s.rdoc_options = [%q{--main}, %q{README.rdoc}, %q{-SHN}, %q{-f}, %q{darkfish}]
s.require_paths = [%q{lib}]
s.rubyforge_project = %q{caldersphere}
s.rubygems_version = %q{1.8.9}
s.summary = %q{CI::Reporter allows you to generate reams of XML for use with continuous integration systems.}
s.test_files = [%q{spec/ci/reporter/cucumber_spec.rb}, %q{spec/ci/reporter/output_capture_spec.rb}, %q{spec/ci/reporter/report_manager_spec.rb}, %q{spec/ci/reporter/rspec_spec.rb}, %q{spec/ci/reporter/test_suite_spec.rb}, %q{spec/ci/reporter/test_unit_spec.rb}, %q{spec/ci/reporter/rake/rake_tasks_spec.rb}]
s.authors = ["Nick Sieger"]
s.date = "2012-01-27"
s.description = "CI::Reporter is an add-on to Test::Unit, RSpec and Cucumber that allows you to generate XML reports of your test, spec and/or feature runs. The resulting files can be read by a continuous integration system that understands Ant's JUnit report XML format, thus allowing your CI system to track test/spec successes and failures."
s.email = "nick@nicksieger.com"
s.extra_rdoc_files = ["History.txt", "LICENSE.txt", "README.rdoc"] + Dir.glob("Manifest.txt")
s.files = ["History.txt", "README.rdoc", "LICENSE.txt", "Rakefile", "stub.rake", "lib/ci/reporter/minitest.rb", "lib/ci/reporter/report_manager.rb", "lib/ci/reporter/test_suite.rb", "lib/ci/reporter/rspec.rb", "lib/ci/reporter/core.rb", "lib/ci/reporter/cucumber.rb", "lib/ci/reporter/rake/minitest.rb", "lib/ci/reporter/rake/minitest_loader.rb", "lib/ci/reporter/rake/cucumber_loader.rb", "lib/ci/reporter/rake/rspec.rb", "lib/ci/reporter/rake/rspec_loader.rb", "lib/ci/reporter/rake/utils.rb", "lib/ci/reporter/rake/test_unit_loader.rb", "lib/ci/reporter/rake/cucumber.rb", "lib/ci/reporter/rake/test_unit.rb", "lib/ci/reporter/test_unit.rb", "lib/ci/reporter/version.rb", "spec/spec_helper.rb", "spec/ci/reporter/rspec_spec.rb", "spec/ci/reporter/test_suite_spec.rb", "spec/ci/reporter/report_manager_spec.rb", "spec/ci/reporter/test_unit_spec.rb", "spec/ci/reporter/rake/rake_tasks_spec.rb", "spec/ci/reporter/cucumber_spec.rb", "spec/ci/reporter/output_capture_spec.rb", "tasks/ci_reporter.rake"]
s.homepage = "http://caldersphere.rubyforge.org/ci_reporter"
s.rdoc_options = ["--main", "README.rdoc", "-SHN", "-f", "darkfish"]
s.require_paths = ["lib"]
s.rubyforge_project = "caldersphere"
s.rubygems_version = "1.8.10"
s.summary = "CI::Reporter allows you to generate reams of XML for use with continuous integration systems."
s.test_files = ["spec/ci/reporter/rspec_spec.rb", "spec/ci/reporter/test_suite_spec.rb", "spec/ci/reporter/report_manager_spec.rb", "spec/ci/reporter/test_unit_spec.rb", "spec/ci/reporter/rake/rake_tasks_spec.rb", "spec/ci/reporter/cucumber_spec.rb", "spec/ci/reporter/output_capture_spec.rb"]

if s.respond_to? :specification_version then
s.specification_version = 3
Expand Down
220 changes: 220 additions & 0 deletions lib/ci/reporter/minitest.rb
@@ -0,0 +1,220 @@
# Copyright (c) 2012 Alexander Shcherbinin <alexander.shcherbinin@gmail.com>
# See the file LICENSE.txt included with the distribution for
# software license details.

require 'ci/reporter/core'

require 'minitest/unit'

module CI
module Reporter
class Failure
def self.new(fault, type = nil, meth = nil)
return MiniTestSkipped.new(fault) if type == :skip
return MiniTestFailure.new(fault, meth) if type == :failure
MiniTestError.new(fault)
end
end

class FailureCore
def location(e)
last_before_assertion = ""
e.backtrace.reverse_each do |s|
break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
last_before_assertion = s
end
last_before_assertion.sub(/:in .*$/, '')
end
end

class MiniTestSkipped < FailureCore
def initialize(fault) @fault = fault end
def failure?() false end
def error?() false end
def name() @fault.class.name end
def message() @fault.message end
def location() super @fault end
end

class MiniTestFailure < FailureCore
def initialize(fault, meth) @fault = fault; @meth = meth end
def failure?() true end
def error?() false end
def name() @meth end
def message() @fault.message end
def location() super @fault end
end

class MiniTestError < FailureCore
def initialize(fault) @fault = fault end
def failure?() false end
def error?() true end
def name() @fault.exception.class.name end
def message() @fault.exception.message end
def location() @fault.exception.backtrace.join("\n") end
end

class Runner < MiniTest::Unit

@@out = $stdout

def initialize
super
@report_manager = ReportManager.new("test")
end

def _run_anything(type)
suites = MiniTest::Unit::TestCase.send "#{type}_suites"
return if suites.empty?

started_anything type

sync = output.respond_to? :"sync=" # stupid emacs
old_sync, output.sync = output.sync, true if sync

_run_suites(suites, type)

output.sync = old_sync if sync

finished_anything(type)
end

def _run_suites(suites, type)
suites.map { |suite| _run_suite suite, type }
end

def _run_suite(suite, type)
start_suite(suite)

header = "#{type}_suite_header"
puts send(header, suite) if respond_to? header

filter_suite_methods(suite, type).each do |method|
_run_test(suite, method)
end

finish_suite
end

def _run_test(suite, method)
start_case(method)

result = run_test(suite, method)

@assertion_count += result._assertions
@test_count += 1

finish_case
end

def puke(klass, meth, e)
e = case e
when MiniTest::Skip then
@skips += 1
fault(e, :skip)
return "S" unless @verbose
"Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
when MiniTest::Assertion then
@failures += 1
fault(e, :failure, meth)
"Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
else
@errors += 1
fault(e, :error)
bt = MiniTest::filter_backtrace(e.backtrace).join "\n "
"Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n"
end
@report << e
e[0, 1]
end

private

def started_anything(type)
@test_count = 0
@assertion_count = 0
@last_assertion_count = 0
@result_assertion_count = 0
@start = Time.now

puts
puts "# Running #{type}s:"
puts
end

def finished_anything(type)
t = Time.now - @start
puts
puts
puts "Finished #{type}s in %.6fs, %.4f tests/s, %.4f assertions/s." %
[t, @test_count / t, @assertion_count / t]

report.each_with_index do |msg, i|
puts "\n%3d) %s" % [i + 1, msg]
end

puts

status
end

def filter_suite_methods(suite, type)
filter = options[:filter] || '/./'
filter = Regexp.new $1 if filter =~ /\/(.*)\//

suite.send("#{type}_methods").grep(filter)
end

def run_test(suite, method)
inst = suite.new method
inst._assertions = 0

print "#{suite}##{method} = " if @verbose

@start_time = Time.now
result = inst.run self
time = Time.now - @start_time

print "%.2f s = " % time if @verbose
print result
puts if @verbose

return inst
end

def start_suite(suite_name)
@current_suite = CI::Reporter::TestSuite.new(suite_name)
@current_suite.start
end

def finish_suite
if @current_suite
@current_suite.finish
@current_suite.assertions = @assertion_count - @last_assertion_count
@last_assertion_count = @assertion_count
@report_manager.write_report(@current_suite)
end
end

def start_case(test_name)
tc = CI::Reporter::TestCase.new(test_name)
tc.start
@current_suite.testcases << tc
end

def finish_case
tc = @current_suite.testcases.last
tc.finish
tc.assertions = @assertion_count - @result_assertion_count
@result_assertion_count = @assertion_count
end

def fault(fault, type = nil, meth = nil)
tc = @current_suite.testcases.last
tc.failures << Failure.new(fault, type, meth)
end

end

end
end
15 changes: 15 additions & 0 deletions lib/ci/reporter/rake/minitest.rb
@@ -0,0 +1,15 @@
# Copyright (c) 2012 Alexander Shcherbinin <alexander.shcherbinin@gmail.com>
# See the file LICENSE.txt included with the distribution for
# software license details.

require File.expand_path('../utils', __FILE__)

namespace :ci do
namespace :setup do
task :minitest do
rm_rf ENV["CI_REPORTS"] || "test/reports"
test_loader = CI::Reporter.maybe_quote_filename "#{File.dirname(__FILE__)}/minitest_loader.rb"
ENV["TESTOPTS"] = "#{ENV["TESTOPTS"]} #{test_loader}"
end
end
end
9 changes: 9 additions & 0 deletions lib/ci/reporter/rake/minitest_loader.rb
@@ -0,0 +1,9 @@
# Copyright (c) 2012 Alexander Shcherbinin <alexander.shcherbinin@gmail.com>
# See the file LICENSE.txt included with the distribution for
# software license details.

$: << File.dirname(__FILE__) + "/../../.."
require 'ci/reporter/minitest'

# set defaults
MiniTest::Unit.runner = CI::Reporter::Runner.new
2 changes: 1 addition & 1 deletion lib/ci/reporter/test_suite.rb
Expand Up @@ -140,7 +140,7 @@ def to_xml(builder)
failures.each do |failure|
tag = case failure.class.name
when /TestUnitSkipped/ then :skipped
when /TestUnitError/ then :error
when /TestUnitError/, /MiniTestError/ then :error
else :failure end

builder.tag!(tag, :type => builder.trunc!(failure.name), :message => builder.trunc!(failure.message)) do
Expand Down
3 changes: 2 additions & 1 deletion stub.rake
Expand Up @@ -2,7 +2,7 @@
# See the file LICENSE.txt included with the distribution for
# software license details.
#
# Use this stub rakefile as a wrapper around a regular Rakefile. Run in the
# Use this stub rakefile as a wrapper around a regular Rakefile. Run in the
# same directory as the real Rakefile.
#
# rake -f /path/to/ci_reporter/lib/ci/reporter/rake/stub.rake ci:setup:rspec default
Expand All @@ -11,4 +11,5 @@
load File.dirname(__FILE__) + '/lib/ci/reporter/rake/rspec.rb'
load File.dirname(__FILE__) + '/lib/ci/reporter/rake/cucumber.rb'
load File.dirname(__FILE__) + '/lib/ci/reporter/rake/test_unit.rb'
load File.dirname(__FILE__) + '/lib/ci/reporter/rake/minitest.rb'
load 'Rakefile'

0 comments on commit cb87ca0

Please sign in to comment.