Browse files

- Major refactoring -- split out reporting core from RSpec

  so we can write a JUnit reporter also



git-svn-id: http://svn.caldersphere.net/svn/main/ci_reporter@53 b03c2d0b-2f10-0410-a2f9-fc8001506dfa
  • Loading branch information...
1 parent 63fb705 commit b8a4915246d3c80459d3a93872aae0545cf40bc9 @nicksieger nicksieger committed Jan 4, 2007
View
4 Rakefile
@@ -2,6 +2,4 @@ require 'spec/rake/spectask'
task :default => :spec
-Spec::Rake::SpecTask.new do |t|
- t.spec_files = FileList["spec/#{ENV['SPECS']}"]
-end
+Spec::Rake::SpecTask.new
View
2 lib/ci/reporter/core.rb
@@ -0,0 +1,2 @@
+require 'ci/reporter/test_suite'
+require 'ci/reporter/report_manager'
View
19 lib/ci/reporter/report_manager.rb
@@ -0,0 +1,19 @@
+require 'fileutils'
+
+module CI
+ module Reporter
+ class ReportManager
+ def initialize(prefix="test")
+ @basedir = ENV['CI_REPORTS'] || File.expand_path("#{Dir.getwd}/#{prefix.downcase}/reports")
+ @basename = "#{@basedir}/#{prefix.upcase}"
+ FileUtils.mkdir_p(@basedir)
+ end
+
+ def write_report(suite)
+ File.open("#{@basename}-#{suite.name.gsub(/[^a-zA-Z0-9]+/, '-')}.xml", "w") do |f|
+ f << suite.to_xml
+ end
+ end
+ end
+ end
+end
View
81 lib/ci/reporter/rspec.rb
@@ -0,0 +1,81 @@
+require 'ci/reporter/core'
+
+module CI
+ module Reporter
+ class RSpecFailure
+ def initialize(failure)
+ @failure = failure
+ end
+
+ def failure?
+ @failure.expectation_not_met?
+ end
+
+ def error?
+ !@failure.expectation_not_met?
+ end
+
+ def exception
+ @failure.exception
+ end
+ end
+
+ class RSpec < Spec::Runner::Formatter::ProgressBarFormatter
+ def initialize(output, dry_run=false, colour=false, report_mgr=nil)
+ super(output, dry_run, colour)
+ @report_manager = report_mgr || ReportManager.new("spec")
+ @suite = nil
+ end
+
+ def start(spec_count)
+ super
+ end
+
+ def add_context(name, first)
+ super
+ write_report if @suite
+ @suite = TestSuite.new name
+ @suite.start
+ end
+
+ def spec_started(name)
+ super
+ spec = TestCase.new name
+ @suite.testcases << spec
+ spec.start
+ end
+
+ def spec_failed(name, counter, failure)
+ super
+ spec = @suite.testcases.last
+ spec.finish
+ spec.failure = RSpecFailure.new(failure)
+ end
+
+ def spec_passed(name)
+ super
+ spec = @suite.testcases.last
+ spec.finish
+ end
+
+ def start_dump
+ super
+ end
+
+ def dump_failure(counter, failure)
+ super
+ end
+
+ def dump_summary(duration, spec_count, failure_count)
+ super
+ write_report
+ end
+
+ private
+ def write_report
+ @suite.finish
+ @report_manager.write_report(@suite)
+ end
+ end
+ end
+end
View
76 lib/rspec_junit_report_formatter.rb → lib/ci/reporter/test_suite.rb
@@ -1,8 +1,6 @@
-require 'fileutils'
-
-module RSpec
- class JUnitReportFormatter < Spec::Runner::Formatter::ProgressBarFormatter
- class Context < Struct.new(:name, :tests, :time, :failures, :errors)
+module CI
+ module Reporter
+ class TestSuite < Struct.new(:name, :tests, :time, :failures, :errors)
attr_accessor :testcases
def initialize(name)
super
@@ -28,7 +26,7 @@ def create_builder
require_gem 'activesupport'
require 'active_support'
rescue
- raise LoadError, "XML Builder is required for the JUnitReportFormatter"
+ raise LoadError, "XML Builder is required by CI::Reporter"
end
end unless defined?(Builder::XmlMarkup)
Builder::XmlMarkup.new(:indent => 2)
@@ -47,7 +45,7 @@ def to_xml
end
end
- class Spec < Struct.new(:name, :time)
+ class TestCase < Struct.new(:name, :time)
attr_accessor :failure
def start
@@ -59,11 +57,11 @@ def finish
end
def failure?
- failure && failure.expectation_not_met?
+ failure && failure.failure?
end
def error?
- failure && !failure.expectation_not_met?
+ failure && failure.error?
end
def to_xml(builder)
@@ -79,65 +77,5 @@ def to_xml(builder)
end
end
end
-
- def initialize(output, dry_run=false, colour=false)
- super
- @basedir = File.expand_path("#{Dir.getwd}/spec/reports")
- @basename = "#{@basedir}/SPEC"
- FileUtils.mkdir_p(@basedir)
- @context = nil
- end
-
- def start(spec_count)
- super
- end
-
- def add_context(name, first)
- super
- write_report if @context
- @context = Context.new name
- @context.start
- end
-
- def spec_started(name)
- super
- spec = Spec.new name
- @context.testcases << spec
- spec.start
- end
-
- def spec_failed(name, counter, failure)
- super
- spec = @context.testcases.last
- spec.finish
- spec.failure = failure
- end
-
- def spec_passed(name)
- super
- spec = @context.testcases.last
- spec.finish
- end
-
- def start_dump
- super
- end
-
- def dump_failure(counter, failure)
- super
- end
-
- def dump_summary(duration, spec_count, failure_count)
- super
- write_report
- end
-
- private
- def write_report
- @context.finish
- File.open("#{@basename}-#{@context.name.gsub(/[^a-zA-Z0-9]+/, '-')}.xml", "w") do |f|
- f << @context.to_xml
- end
- end
end
end
View
21 lib/ci/reporter/test_unit.rb
@@ -0,0 +1,21 @@
+module CI
+ module Reporter
+ class TestUnitFailure
+ def failure?
+
+ end
+
+ def error?
+
+ end
+
+ def exception
+
+ end
+ end
+
+ class TestUnit
+
+ end
+ end
+end
View
35 spec/ci/reporter/report_manager_spec.rb
@@ -0,0 +1,35 @@
+require File.dirname(__FILE__) + "/../../spec_helper.rb"
+
+context "The ReportManager" do
+ setup do
+ @reports_dir = REPORTS_DIR
+ end
+
+ teardown do
+ FileUtils.rm_rf @reports_dir
+ ENV["CI_REPORTS"] = nil
+ end
+
+ specify "should create the report directory according to the given prefix" do
+ CI::Reporter::ReportManager.new("spec")
+ File.directory?(@reports_dir).should_be true
+ end
+
+ specify "should create the report directory based on CI_REPORTS environment variable if set" do
+ @reports_dir = "#{Dir.getwd}/dummy"
+ ENV["CI_REPORTS"] = @reports_dir
+ CI::Reporter::ReportManager.new("spec")
+ File.directory?(@reports_dir).should_be true
+ end
+
+ specify "should write reports based on name and xml content of a test suite" do
+ reporter = CI::Reporter::ReportManager.new("spec")
+ suite = mock("test suite")
+ suite.should_receive(:name).and_return("some test suite name")
+ suite.should_receive(:to_xml).and_return("<xml></xml>")
+ reporter.write_report(suite)
+ filename = "#{REPORTS_DIR}/SPEC-some-test-suite-name.xml"
+ File.exist?(filename).should_be true
+ File.open(filename) {|f| f.read.should == "<xml></xml>"}
+ end
+end
View
35 spec/ci/reporter/rspec_spec.rb
@@ -0,0 +1,35 @@
+require File.dirname(__FILE__) + "/../../spec_helper.rb"
+require 'stringio'
+
+context "The RSpec reporter" do
+ setup do
+ @error = mock("error")
+ @error.stub!(:exception).and_return do
+ begin
+ raise StandardError, "error message"
+ rescue => e
+ e
+ end
+ end
+ @error.stub!(:expectation_not_met?).and_return(false)
+ @report_mgr = mock("report manager")
+ @fmt = CI::Reporter::RSpec.new(StringIO.new(""), false, false, @report_mgr)
+ end
+
+ specify "should create a test suite with one success and one failure" do
+ @report_mgr.should_receive(:write_report).and_return do |suite|
+ suite.testcases.length.should == 2
+ suite.testcases.first.should_not_be_failure
+ suite.testcases.first.should_not_be_error
+ suite.testcases.last.should_be_error
+ end
+
+ @fmt.start(2)
+ @fmt.add_context("A context", true)
+ @fmt.spec_started("should pass")
+ @fmt.spec_passed("should pass")
+ @fmt.spec_started("should fail")
+ @fmt.spec_failed("should fail", 1, @error)
+ @fmt.dump_summary(0.1, 2, 1)
+ end
+end
View
95 spec/ci/reporter/test_suite_spec.rb
@@ -0,0 +1,95 @@
+require File.dirname(__FILE__) + "/../../spec_helper.rb"
+require 'rexml/document'
+
+context "A TestSuite" do
+ setup do
+ @suite = CI::Reporter::TestSuite.new("example suite")
+ end
+
+ specify "should collect timings when start and finish are invoked in sequence" do
+ @suite.start
+ @suite.finish
+ @suite.time.should_be > 0
+ end
+
+ specify "should aggregate tests" do
+ @suite.start
+ @suite.testcases << CI::Reporter::TestCase.new("example test")
+ @suite.finish
+ @suite.tests.should == 1
+ end
+
+ specify "should indicate number of failures and errors" do
+ failure = mock("failure")
+ failure.stub!(:failure?).and_return true
+ failure.stub!(:error?).and_return false
+
+ error = mock("error")
+ error.stub!(:failure?).and_return false
+ error.stub!(:error?).and_return true
+
+ @suite.start
+ @suite.testcases << CI::Reporter::TestCase.new("example test")
+ @suite.testcases << CI::Reporter::TestCase.new("failure test")
+ @suite.testcases.last.failure = failure
+ @suite.testcases << CI::Reporter::TestCase.new("error test")
+ @suite.testcases.last.failure = error
+ @suite.finish
+ @suite.tests.should == 3
+ @suite.failures.should == 1
+ @suite.errors.should == 1
+ end
+
+end
+
+context "TestSuite xml" do
+ setup do
+ @suite = CI::Reporter::TestSuite.new("example suite")
+ begin
+ raise StandardError, "an exception occurred"
+ rescue => e
+ @exception = e
+ end
+ end
+
+ specify "should contain Ant/JUnit-formatted description of entire suite" do
+ failure = mock("failure")
+ failure.stub!(:failure?).and_return true
+ failure.stub!(:error?).and_return false
+ failure.stub!(:exception).and_return @exception
+
+ error = mock("error")
+ error.stub!(:failure?).and_return false
+ error.stub!(:error?).and_return true
+ error.stub!(:exception).and_return @exception
+
+ @suite.start
+ @suite.testcases << CI::Reporter::TestCase.new("example test")
+ @suite.testcases << CI::Reporter::TestCase.new("failure test")
+ @suite.testcases.last.failure = failure
+ @suite.testcases << CI::Reporter::TestCase.new("error test")
+ @suite.testcases.last.failure = error
+ @suite.finish
+
+ xml = @suite.to_xml
+ doc = REXML::Document.new(xml)
+ testsuite = doc.root.elements.to_a('/testsuite')
+ testsuite.length.should == 1
+ testsuite = testsuite.first
+
+ testcases = testsuite.elements.to_a('testcase')
+ testcases.length.should == 3
+ end
+end
+
+context "A TestCase" do
+ setup do
+ @tc = CI::Reporter::TestCase.new("example test")
+ end
+
+ specify "should collect timings when start and finish are invoked in sequence" do
+ @tc.start
+ @tc.finish
+ @tc.time.should_be > 0
+ end
+end
View
45 spec/rspec_junit_report_formatter_spec.rb
@@ -1,45 +0,0 @@
-require 'stringio'
-require 'rexml/document'
-require 'rubygems'
-require_gem 'rspec'
-require 'spec'
-require File.dirname(__FILE__) + '/../lib/rspec_junit_report_formatter'
-
-context "The JUnitReportFormatter" do
- setup do
- @reports_dir = File.dirname(__FILE__) + "/reports"
-
- @failure = mock("failure")
- @failure.stub!(:exception).and_return do
- begin
- raise StandardError, "failure message"
- rescue => e
- e
- end
- end
- @failure.stub!(:expectation_not_met?).and_return(false)
-
- @io = StringIO.new("")
- @fmt = RSpec::JUnitReportFormatter.new(@io)
- end
-
- teardown do
- FileUtils.rm_rf(@reports_dir)
- end
-
- specify "should create an XML file with one success and one failure" do
- @fmt.start(2)
- @fmt.add_context("A context", true)
- @fmt.spec_started("should pass")
- @fmt.spec_passed("should pass")
- @fmt.spec_started("should fail")
- @fmt.spec_failed("should fail", 1, @failure)
- @fmt.dump_summary(0.1, 2, 1)
- spec_file = Dir["#{@reports_dir}/*.xml"].to_a
- spec_file.length.should == 1
- spec_file = spec_file.first
- doc = File.open(spec_file) {|f| REXML::Document.new(f) }
- doc.root.elements.to_a("//testcase").length.should == 2
- doc.root.elements.to_a("//testcase/failure").length.should == 1
- end
-end
View
9 spec/spec_helper.rb
@@ -0,0 +1,9 @@
+require 'rubygems'
+require_gem 'rspec'
+require 'spec'
+$: << File.dirname(__FILE__) + "/../lib"
+require 'ci/reporter/core'
+# require 'ci/reporter/test_unit'
+require 'ci/reporter/rspec'
+
+REPORTS_DIR = File.dirname(__FILE__) + "/reports"
View
7 tasks/ci_reporter.rake
@@ -0,0 +1,7 @@
+namespace :ci do
+ task :setup_rspec do
+ rm_rf "spec/reports"
+ ENV['RSPECOPTS'] = ["--require", "#{File.dirname(__FILE__)}/rspec.rb",
+ "--format", "CI::Reporter::RSpec"].join(" ")
+ end
+end
View
8 tasks/junit_formatter.rake
@@ -1,8 +0,0 @@
-SPEC_OPTS = []
-namespace :spec do
- task :setupxml do
- rm_rf "spec/reports"
- ENV['RSPECOPTS'] = ["--require", "#{File.dirname(__FILE__)}/../lib/rspec_junit_report_formatter",
- "--format", "RSpec::JUnitReportFormatter"].join(" ")
- end
-end
View
2 tasks/rspec.rb
@@ -0,0 +1,2 @@
+$: << File.dirname(__FILE__) + "/../lib"
+require 'ci/reporter/rspec'

0 comments on commit b8a4915

Please sign in to comment.