ci_reporter 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ == 1.0
2
+
3
+ Initial Release.
@@ -0,0 +1,19 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/ci/reporter/core.rb
6
+ lib/ci/reporter/report_manager.rb
7
+ lib/ci/reporter/rspec.rb
8
+ lib/ci/reporter/test_suite.rb
9
+ lib/ci/reporter/test_unit.rb
10
+ lib/ci/reporter/rake/rspec.rb
11
+ lib/ci/reporter/rake/rspec_loader.rb
12
+ lib/ci/reporter/rake/test_unit.rb
13
+ lib/ci/reporter/rake/test_unit_loader.rb
14
+ spec/spec_helper.rb
15
+ spec/ci/reporter/report_manager_spec.rb
16
+ spec/ci/reporter/rspec_spec.rb
17
+ spec/ci/reporter/test_suite_spec.rb
18
+ spec/ci/reporter/test_unit_spec.rb
19
+ tasks/ci_reporter.rake
@@ -0,0 +1,45 @@
1
+ CI::Reporter is an add-on to Test::Unit and RSpec that allows you to generate
2
+ XML reports of your test and/or spec runs. The resulting files can be read by
3
+ a continuous integration system that understands Ant's JUnit report XML
4
+ format, thus allowing your CI system to track test/spec successes and
5
+ failures.
6
+
7
+ == Dependencies
8
+
9
+ CI::Reporter has one required dependency on Builder, but since many will have a viable version of Builder via Rails' ActiveSupport gem, Builder is not a direct dependency of the project at the moment. Instead, ensure that you have either the +builder+ or +activesupport+ gem installed before continuing.
10
+
11
+ == Installation
12
+
13
+ CI::Reporter is available as a gem. To install the gem, use the usual gem command:
14
+
15
+ gem install ci_reporter
16
+
17
+ To use CI::Reporter as a Rails plugin, first install the gem, and then install the plugin as follows:
18
+
19
+ script/plugin install http://svn.caldersphere.net/svn/main/plugins/ci_reporter
20
+
21
+ == Usage
22
+
23
+ CI::Reporter works best with projects that use a +Rakefile+ along with the standard <code>Rake::TestTask</code> or <code>Spec::Rake::SpecTask</code> tasks for running tests or specs, respectively. In this fashion, it hooks into <code>Test::Unit</code> or +RSpec+ using environment variables recognized by these custom tasks to inject the CI::Reporter code into the test or spec runs. If you're using the Rails plugin, step 1 is unnecessary; skip to step 2.
24
+
25
+ 1. To use CI::Reporter, simply add the following lines to your Rakefile:
26
+
27
+ require 'rubygems'
28
+ gem 'ci_reporter'
29
+ require 'ci/reporter/rake/rspec' # use this if you're using RSpec
30
+ require 'ci/reporter/rake/test_unit' # use this if you're using Test::Unit
31
+
32
+ 2. Next, either modify your Rakefile to make the <code>ci:setup:rspec</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.
33
+
34
+ rake ci:setup:testunit test
35
+
36
+ == Advanced Usage
37
+
38
+ If for some reason you can't use the above technique to inject CI::Reporter, you'll have to do one of these:
39
+
40
+ 1. If you're using <code>Test::Unit</code>, ensure the <code>ci/reporter/rake/test_unit_loader.rb</code> file is loaded or required at some point before the tests are run.
41
+ 2. If you're using +RSpec+, you'll need to pass the following arguments to the +spec+ command:
42
+ --require GEM_PATH/lib/ci/reporter/rake/rspec_loader
43
+ --format CI::Reporter::RSpec
44
+
45
+ There's a bit of a chicken and egg problem because rubygems needs to be loaded before you can require any CI::Reporter files. If you cringe hard-coding a full path to a specific version of the gem, you can also copy the +rspec_loader+ file into your project and require it directly -- the contents are version-agnostic and are not likely to change in future releases.
@@ -0,0 +1,34 @@
1
+ require 'spec/rake/spectask'
2
+ require 'hoe'
3
+
4
+ MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt", "Rakefile",
5
+ "lib/**/*.rb", "spec/**/*.rb", "tasks/**/*.rake"]
6
+
7
+ Hoe.new("ci_reporter", "1.0") do |p|
8
+ p.rubyforge_name = "caldersphere"
9
+ p.url = "http://caldersphere.rubyforge.org/ci_reporter"
10
+ p.author = "Nick Sieger"
11
+ p.email = "nick@nicksieger.com"
12
+ p.summary = "CI::Reporter allows you to generate reams of XML for use with continuous integration systems."
13
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
14
+ p.description = p.paragraphs_of('README.txt', 0...1).join("\n\n")
15
+ p.extra_deps.reject!{|d| d.first == "hoe"}
16
+ p.test_globs = ["spec/**/*_spec.rb"]
17
+ end.spec.files = MANIFEST
18
+
19
+ # Hoe insists on setting task :default => :test
20
+ # !@#$ no easy way to empty the default list of prerequisites
21
+ Rake::Task['default'].send :instance_variable_set, "@prerequisites", FileList[]
22
+
23
+ task :default => :spec
24
+
25
+ Spec::Rake::SpecTask.new do |t|
26
+ t.spec_opts = ["--diff", "unified"]
27
+ end
28
+
29
+ # Automated manifest
30
+ task :manifest do
31
+ File.open("Manifest.txt", "w") {|f| MANIFEST.each {|n| f << "#{n}\n"} }
32
+ end
33
+
34
+ task :package => :manifest
@@ -0,0 +1,2 @@
1
+ require 'ci/reporter/test_suite'
2
+ require 'ci/reporter/report_manager'
@@ -0,0 +1,9 @@
1
+ namespace :ci do
2
+ namespace :setup do
3
+ task :rspec do
4
+ rm_rf ENV["CI_REPORTS"] || "spec/reports"
5
+ ENV["RSPECOPTS"] = ["--require", "#{File.dirname(__FILE__)}/rspec_loader.rb",
6
+ "--format", "CI::Reporter::RSpec"].join(" ")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ begin
3
+ gem 'ci_reporter'
4
+ rescue => e
5
+ $: << File.dirname(__FILE__) + "/../../../lib"
6
+ end
7
+ require 'ci/reporter/rspec'
@@ -0,0 +1,8 @@
1
+ namespace :ci do
2
+ namespace :setup do
3
+ task :testunit do
4
+ rm_rf ENV["CI_REPORTS"] || "test/reports"
5
+ ENV["TESTOPTS"] = "#{File.dirname(__FILE__)}/test_unit_loader.rb"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ begin
3
+ gem 'ci_reporter'
4
+ rescue
5
+ $: << File.dirname(__FILE__) + "/../../../lib"
6
+ end
7
+ require 'ci/reporter/test_unit'
8
+
9
+ module Test #:nodoc:all
10
+ module Unit
11
+ module UI
12
+ module Console
13
+ class TestRunner
14
+ def create_mediator(suite)
15
+ # swap in our custom mediator
16
+ return CI::Reporter::TestUnit.new(suite)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ require 'fileutils'
2
+
3
+ module CI #:nodoc:
4
+ module Reporter #:nodoc:
5
+ class ReportManager
6
+ def initialize(prefix)
7
+ @basedir = ENV['CI_REPORTS'] || File.expand_path("#{Dir.getwd}/#{prefix.downcase}/reports")
8
+ @basename = "#{@basedir}/#{prefix.upcase}"
9
+ FileUtils.mkdir_p(@basedir)
10
+ end
11
+
12
+ def write_report(suite)
13
+ File.open("#{@basename}-#{suite.name.gsub(/[^a-zA-Z0-9]+/, '-')}.xml", "w") do |f|
14
+ f << suite.to_xml
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,85 @@
1
+ require 'ci/reporter/core'
2
+ gem 'rspec'
3
+ require 'spec'
4
+
5
+ module CI
6
+ module Reporter
7
+ # Wrapper around a <code>RSpec</code> error or failure to be used by the test suite to interpret results.
8
+ class RSpecFailure
9
+ def initialize(failure)
10
+ @failure = failure
11
+ end
12
+
13
+ def failure?
14
+ @failure.expectation_not_met?
15
+ end
16
+
17
+ def error?
18
+ !@failure.expectation_not_met?
19
+ end
20
+
21
+ def name() @failure.exception.class.name end
22
+ def message() @failure.exception.message end
23
+ def location() @failure.exception.backtrace.join("\n") end
24
+ end
25
+
26
+ # Custom +RSpec+ formatter used to hook into the spec runs and capture results.
27
+ class RSpec < Spec::Runner::Formatter::ProgressBarFormatter
28
+ def initialize(output, dry_run=false, colour=false, report_mgr=nil)
29
+ super(output, dry_run, colour)
30
+ @report_manager = report_mgr || ReportManager.new("spec")
31
+ @suite = nil
32
+ end
33
+
34
+ def start(spec_count)
35
+ super
36
+ end
37
+
38
+ def add_context(name, first)
39
+ super
40
+ write_report if @suite
41
+ @suite = TestSuite.new name
42
+ @suite.start
43
+ end
44
+
45
+ def spec_started(name)
46
+ super
47
+ spec = TestCase.new name
48
+ @suite.testcases << spec
49
+ spec.start
50
+ end
51
+
52
+ def spec_failed(name, counter, failure)
53
+ super
54
+ spec = @suite.testcases.last
55
+ spec.finish
56
+ spec.failure = RSpecFailure.new(failure)
57
+ end
58
+
59
+ def spec_passed(name)
60
+ super
61
+ spec = @suite.testcases.last
62
+ spec.finish
63
+ end
64
+
65
+ def start_dump
66
+ super
67
+ end
68
+
69
+ def dump_failure(counter, failure)
70
+ super
71
+ end
72
+
73
+ def dump_summary(duration, spec_count, failure_count)
74
+ super
75
+ write_report
76
+ end
77
+
78
+ private
79
+ def write_report
80
+ @suite.finish
81
+ @report_manager.write_report(@suite)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,103 @@
1
+ module CI
2
+ module Reporter
3
+ # Basic structure representing the running of a test suite. Used to time tests and store results.
4
+ class TestSuite < Struct.new(:name, :tests, :time, :failures, :errors)
5
+ attr_accessor :testcases
6
+ def initialize(name)
7
+ super
8
+ @testcases = []
9
+ end
10
+
11
+ # Starts timing the test suite.
12
+ def start
13
+ @start = Time.now
14
+ end
15
+
16
+ # Finishes timing the test suite.
17
+ def finish
18
+ self.tests = testcases.size
19
+ self.time = Time.now - @start
20
+ self.failures = testcases.select {|tc| tc.failure? }.size
21
+ self.errors = testcases.select {|tc| tc.error? }.size
22
+ end
23
+
24
+ # Creates the xml builder instance used to create the report xml document.
25
+ def create_builder
26
+ begin
27
+ gem 'builder'
28
+ require 'builder'
29
+ rescue
30
+ begin
31
+ gem 'activesupport'
32
+ require 'active_support'
33
+ rescue
34
+ raise LoadError, "XML Builder is required by CI::Reporter"
35
+ end
36
+ end unless defined?(Builder::XmlMarkup)
37
+ # :escape_attrs is obsolete in a newer version, but should do no harm
38
+ Builder::XmlMarkup.new(:indent => 2, :escape_attrs => true)
39
+ end
40
+
41
+ # Creates an xml string containing the test suite results.
42
+ def to_xml
43
+ builder = create_builder
44
+ # more recent version of Builder doesn't need the escaping
45
+ if Builder::XmlMarkup.private_instance_methods.include?("_attr_value")
46
+ def builder.trunc!(txt)
47
+ txt.sub(/\n.*/m, '...')
48
+ end
49
+ else
50
+ def builder.trunc!(txt)
51
+ _escape(txt.sub(/\n.*/m, '...'))
52
+ end
53
+ end
54
+ builder.instruct!
55
+ attrs = {}
56
+ each_pair {|k,v| attrs[k] = builder.trunc!(v.to_s) }
57
+ builder.testsuite(attrs) do
58
+ @testcases.each do |tc|
59
+ tc.to_xml(builder)
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ # Structure used to represent an individual test case. Used to time the test and store the result.
66
+ class TestCase < Struct.new(:name, :time)
67
+ attr_accessor :failure
68
+
69
+ # Starts timing the test.
70
+ def start
71
+ @start = Time.now
72
+ end
73
+
74
+ # Finishes timing the test.
75
+ def finish
76
+ self.time = Time.now - @start
77
+ end
78
+
79
+ # Returns non-nil if the test failed.
80
+ def failure?
81
+ failure && failure.failure?
82
+ end
83
+
84
+ # Returns non-nil if the test had an error.
85
+ def error?
86
+ failure && failure.error?
87
+ end
88
+
89
+ # Writes xml representing the test result to the provided builder.
90
+ def to_xml(builder)
91
+ attrs = {}
92
+ each_pair {|k,v| attrs[k] = builder.trunc!(v.to_s) }
93
+ builder.testcase(attrs) do
94
+ if failure
95
+ builder.failure(:type => builder.trunc!(failure.name), :message => builder.trunc!(failure.message)) do
96
+ builder.text!(failure.location)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,113 @@
1
+ require 'ci/reporter/core'
2
+ require 'test/unit'
3
+ require 'test/unit/ui/console/testrunner'
4
+
5
+ module CI
6
+ module Reporter
7
+ # Factory for constructing either a CI::Reporter::TestUnitFailure or CI::Reporter::TestUnitError depending on the result
8
+ # of the test.
9
+ class Failure
10
+ def self.new(fault)
11
+ fault.kind_of?(Test::Unit::Failure) ? TestUnitFailure.new(fault) : TestUnitError.new(fault)
12
+ end
13
+ end
14
+
15
+ # Wrapper around a <code>Test::Unit</code> error to be used by the test suite to interpret results.
16
+ class TestUnitError
17
+ def initialize(fault)
18
+ @fault = fault
19
+ end
20
+ def failure?() false end
21
+ def error?() true end
22
+ def name() @fault.exception.class.name end
23
+ def message() @fault.exception.message end
24
+ def location() @fault.exception.backtrace.join("\n") end
25
+ end
26
+
27
+ # Wrapper around a <code>Test::Unit</code> failure to be used by the test suite to interpret results.
28
+ class TestUnitFailure
29
+ def initialize(fault)
30
+ @fault = fault
31
+ end
32
+ def failure?() true end
33
+ def error?() false end
34
+ def name() Test::Unit::AssertionFailedError.name end
35
+ def message() @fault.message end
36
+ def location() @fault.location.join("\n") end
37
+ end
38
+
39
+ # Replacement Mediator that adds listeners to capture the results of the <code>Test::Unit</code> runs.
40
+ class TestUnit < Test::Unit::UI::TestRunnerMediator
41
+ def initialize(suite, report_mgr = nil)
42
+ super(suite)
43
+ @report_manager = report_mgr || ReportManager.new("test")
44
+ add_listener(Test::Unit::UI::TestRunnerMediator::STARTED, &method(:started))
45
+ add_listener(Test::Unit::TestCase::STARTED, &method(:test_started))
46
+ add_listener(Test::Unit::TestCase::FINISHED, &method(:test_finished))
47
+ add_listener(Test::Unit::TestResult::FAULT, &method(:fault))
48
+ add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED, &method(:finished))
49
+ end
50
+
51
+ def started(result)
52
+ @current_suite = nil
53
+ @unknown_count = 0
54
+ end
55
+
56
+ def test_started(name)
57
+ test_name, suite_name = extract_names(name)
58
+ unless @current_suite && @current_suite.name == suite_name
59
+ finish_suite
60
+ start_suite(suite_name)
61
+ end
62
+ start_test(test_name)
63
+ end
64
+
65
+ def test_finished(name)
66
+ finish_test
67
+ end
68
+
69
+ def fault(fault)
70
+ finish_test(fault)
71
+ end
72
+
73
+ def finished(elapsed_time)
74
+ finish_suite
75
+ end
76
+
77
+ private
78
+ def extract_names(name)
79
+ match = name.match(/(.*)\(([^)]*)\)/)
80
+ if match
81
+ [match[1], match[2]]
82
+ else
83
+ @unknown_count += 1
84
+ [name, "unknown-#{@unknown_count}"]
85
+ end
86
+ end
87
+
88
+ def start_suite(suite_name)
89
+ @current_suite = TestSuite.new(suite_name)
90
+ @current_suite.start
91
+ end
92
+
93
+ def finish_suite
94
+ if @current_suite
95
+ @current_suite.finish
96
+ @report_manager.write_report(@current_suite)
97
+ end
98
+ end
99
+
100
+ def start_test(test_name)
101
+ tc = TestCase.new(test_name)
102
+ tc.start
103
+ @current_suite.testcases << tc
104
+ end
105
+
106
+ def finish_test(failure = nil)
107
+ tc = @current_suite.testcases.last
108
+ tc.finish
109
+ tc.failure = Failure.new(failure) if failure
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + "/../../spec_helper.rb"
2
+
3
+ context "The ReportManager" do
4
+ setup do
5
+ @reports_dir = REPORTS_DIR
6
+ end
7
+
8
+ teardown do
9
+ FileUtils.rm_rf @reports_dir
10
+ ENV["CI_REPORTS"] = nil
11
+ end
12
+
13
+ specify "should create the report directory according to the given prefix" do
14
+ CI::Reporter::ReportManager.new("spec")
15
+ File.directory?(@reports_dir).should_be true
16
+ end
17
+
18
+ specify "should create the report directory based on CI_REPORTS environment variable if set" do
19
+ @reports_dir = "#{Dir.getwd}/dummy"
20
+ ENV["CI_REPORTS"] = @reports_dir
21
+ CI::Reporter::ReportManager.new("spec")
22
+ File.directory?(@reports_dir).should_be true
23
+ end
24
+
25
+ specify "should write reports based on name and xml content of a test suite" do
26
+ reporter = CI::Reporter::ReportManager.new("spec")
27
+ suite = mock("test suite")
28
+ suite.should_receive(:name).and_return("some test suite name")
29
+ suite.should_receive(:to_xml).and_return("<xml></xml>")
30
+ reporter.write_report(suite)
31
+ filename = "#{REPORTS_DIR}/SPEC-some-test-suite-name.xml"
32
+ File.exist?(filename).should_be true
33
+ File.open(filename) {|f| f.read.should == "<xml></xml>"}
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + "/../../spec_helper.rb"
2
+ require 'stringio'
3
+
4
+ context "The RSpec reporter" do
5
+ setup do
6
+ @error = mock("error")
7
+ @error.stub!(:exception).and_return do
8
+ begin
9
+ raise StandardError, "error message"
10
+ rescue => e
11
+ e
12
+ end
13
+ end
14
+ @error.stub!(:expectation_not_met?).and_return(false)
15
+ @report_mgr = mock("report manager")
16
+ @fmt = CI::Reporter::RSpec.new(StringIO.new(""), false, false, @report_mgr)
17
+ end
18
+
19
+ specify "should create a test suite with one success and one failure" do
20
+ @report_mgr.should_receive(:write_report).and_return do |suite|
21
+ suite.testcases.length.should == 2
22
+ suite.testcases.first.should_not_be_failure
23
+ suite.testcases.first.should_not_be_error
24
+ suite.testcases.last.should_be_error
25
+ end
26
+
27
+ @fmt.start(2)
28
+ @fmt.add_context("A context", true)
29
+ @fmt.spec_started("should pass")
30
+ @fmt.spec_passed("should pass")
31
+ @fmt.spec_started("should fail")
32
+ @fmt.spec_failed("should fail", 1, @error)
33
+ @fmt.dump_summary(0.1, 2, 1)
34
+ end
35
+ end
@@ -0,0 +1,116 @@
1
+ require File.dirname(__FILE__) + "/../../spec_helper.rb"
2
+ require 'rexml/document'
3
+
4
+ context "A TestSuite" do
5
+ setup do
6
+ @suite = CI::Reporter::TestSuite.new("example suite")
7
+ end
8
+
9
+ specify "should collect timings when start and finish are invoked in sequence" do
10
+ @suite.start
11
+ @suite.finish
12
+ @suite.time.should_be > 0
13
+ end
14
+
15
+ specify "should aggregate tests" do
16
+ @suite.start
17
+ @suite.testcases << CI::Reporter::TestCase.new("example test")
18
+ @suite.finish
19
+ @suite.tests.should == 1
20
+ end
21
+
22
+ specify "should indicate number of failures and errors" do
23
+ failure = mock("failure")
24
+ failure.stub!(:failure?).and_return true
25
+ failure.stub!(:error?).and_return false
26
+
27
+ error = mock("error")
28
+ error.stub!(:failure?).and_return false
29
+ error.stub!(:error?).and_return true
30
+
31
+ @suite.start
32
+ @suite.testcases << CI::Reporter::TestCase.new("example test")
33
+ @suite.testcases << CI::Reporter::TestCase.new("failure test")
34
+ @suite.testcases.last.failure = failure
35
+ @suite.testcases << CI::Reporter::TestCase.new("error test")
36
+ @suite.testcases.last.failure = error
37
+ @suite.finish
38
+ @suite.tests.should == 3
39
+ @suite.failures.should == 1
40
+ @suite.errors.should == 1
41
+ end
42
+
43
+ end
44
+
45
+ context "TestSuite xml" do
46
+ setup do
47
+ @suite = CI::Reporter::TestSuite.new("example suite")
48
+ begin
49
+ raise StandardError, "an exception occurred"
50
+ rescue => e
51
+ @exception = e
52
+ end
53
+ end
54
+
55
+ specify "should contain Ant/JUnit-formatted description of entire suite" do
56
+ failure = mock("failure")
57
+ failure.stub!(:failure?).and_return true
58
+ failure.stub!(:error?).and_return false
59
+ failure.stub!(:name).and_return "failure"
60
+ failure.stub!(:message).and_return "There was a failure"
61
+ failure.stub!(:location).and_return @exception.backtrace.join("\n")
62
+
63
+ error = mock("error")
64
+ error.stub!(:failure?).and_return false
65
+ error.stub!(:error?).and_return true
66
+ error.stub!(:name).and_return "error"
67
+ error.stub!(:message).and_return "There was a error"
68
+ error.stub!(:location).and_return @exception.backtrace.join("\n")
69
+
70
+ @suite.start
71
+ @suite.testcases << CI::Reporter::TestCase.new("example test")
72
+ @suite.testcases << CI::Reporter::TestCase.new("failure test")
73
+ @suite.testcases.last.failure = failure
74
+ @suite.testcases << CI::Reporter::TestCase.new("error test")
75
+ @suite.testcases.last.failure = error
76
+ @suite.finish
77
+
78
+ xml = @suite.to_xml
79
+ doc = REXML::Document.new(xml)
80
+ testsuite = doc.root.elements.to_a('/testsuite')
81
+ testsuite.length.should == 1
82
+ testsuite = testsuite.first
83
+
84
+ testcases = testsuite.elements.to_a('testcase')
85
+ testcases.length.should == 3
86
+ end
87
+
88
+ specify "should filter attributes properly for invalid characters" do
89
+ failure = mock("failure")
90
+ failure.stub!(:failure?).and_return true
91
+ failure.stub!(:error?).and_return false
92
+ failure.stub!(:name).and_return "failure"
93
+ failure.stub!(:message).and_return "There was a <failure>\nReason: blah"
94
+ failure.stub!(:location).and_return @exception.backtrace.join("\n")
95
+
96
+ @suite.start
97
+ @suite.testcases << CI::Reporter::TestCase.new("failure test")
98
+ @suite.testcases.last.failure = failure
99
+ @suite.finish
100
+
101
+ xml = @suite.to_xml
102
+ xml.should_match %r/message="There was a &lt;failure&gt;\.\.\."/
103
+ end
104
+ end
105
+
106
+ context "A TestCase" do
107
+ setup do
108
+ @tc = CI::Reporter::TestCase.new("example test")
109
+ end
110
+
111
+ specify "should collect timings when start and finish are invoked in sequence" do
112
+ @tc.start
113
+ @tc.finish
114
+ @tc.time.should_be > 0
115
+ end
116
+ end
@@ -0,0 +1,75 @@
1
+ require File.dirname(__FILE__) + "/../../spec_helper.rb"
2
+
3
+ context "The TestUnit reporter" do
4
+ setup do
5
+ @report_mgr = mock("report manager")
6
+ @testunit = CI::Reporter::TestUnit.new(nil, @report_mgr)
7
+ end
8
+
9
+ specify "should build suites based on adjacent tests with the same class name" do
10
+ @suite = nil
11
+ @report_mgr.should_receive(:write_report).once.and_return {|suite| @suite = suite }
12
+
13
+ @testunit.started(mock("result"))
14
+ @testunit.test_started("test_one(TestCaseClass)")
15
+ @testunit.test_finished("test_one(TestCaseClass)")
16
+ @testunit.test_started("test_two(TestCaseClass)")
17
+ @testunit.test_finished("test_two(TestCaseClass)")
18
+ @testunit.finished(10)
19
+
20
+ @suite.name.should == "TestCaseClass"
21
+ @suite.testcases.length.should == 2
22
+ @suite.testcases.first.name.should == "test_one"
23
+ @suite.testcases.first.should_not_be_failure
24
+ @suite.testcases.first.should_not_be_error
25
+ @suite.testcases.last.name.should == "test_two"
26
+ @suite.testcases.last.should_not_be_failure
27
+ @suite.testcases.last.should_not_be_error
28
+ end
29
+
30
+ specify "should build two suites when encountering different class names" do
31
+ @suites = []
32
+ @report_mgr.should_receive(:write_report).twice.and_return {|suite| @suites << suite }
33
+
34
+ @testunit.started(mock("result"))
35
+ @testunit.test_started("test_one(TestCaseClass)")
36
+ @testunit.test_finished("test_one(TestCaseClass)")
37
+ @testunit.test_started("test_two(AnotherTestCaseClass)")
38
+ @testunit.test_finished("test_two(AnotherTestCaseClass)")
39
+ @testunit.finished(10)
40
+
41
+ @suites.first.name.should == "TestCaseClass"
42
+ @suites.first.testcases.length.should == 1
43
+ @suites.first.testcases.first.name.should == "test_one"
44
+ @suites.last.name.should == "AnotherTestCaseClass"
45
+ @suites.last.testcases.length.should == 1
46
+ @suites.last.testcases.first.name.should == "test_two"
47
+ end
48
+
49
+ specify "should add failures to testcases when encountering a fault" do
50
+ begin
51
+ raise StandardError, "error"
52
+ rescue => e
53
+ @error = Test::Unit::Error.new("test_two(TestCaseClass)", e)
54
+ end
55
+
56
+ @suite = nil
57
+ @report_mgr.should_receive(:write_report).once.and_return {|suite| @suite = suite }
58
+
59
+ @testunit.started(mock("result"))
60
+ @testunit.test_started("test_one(TestCaseClass)")
61
+ @testunit.test_finished("test_one(TestCaseClass)")
62
+ @testunit.test_started("test_two(TestCaseClass)")
63
+ @testunit.fault(@error)
64
+ @testunit.finished(10)
65
+
66
+ @suite.name.should == "TestCaseClass"
67
+ @suite.testcases.length.should == 2
68
+ @suite.testcases.first.name.should == "test_one"
69
+ @suite.testcases.first.should_not_be_failure
70
+ @suite.testcases.first.should_not_be_error
71
+ @suite.testcases.last.name.should == "test_two"
72
+ @suite.testcases.last.should_not_be_failure
73
+ @suite.testcases.last.should_be_error
74
+ end
75
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ gem 'rspec'
3
+ require 'spec'
4
+ $: << File.dirname(__FILE__) + "/../lib"
5
+ require 'ci/reporter/core'
6
+ require 'ci/reporter/test_unit'
7
+ require 'ci/reporter/rspec'
8
+
9
+ REPORTS_DIR = File.dirname(__FILE__) + "/reports"
@@ -0,0 +1,12 @@
1
+ begin
2
+ gem 'ci_reporter'
3
+ rescue
4
+ $: << File.dirname(__FILE__) + "/../lib"
5
+ end
6
+ require 'ci/reporter/rake/rspec'
7
+ require 'ci/reporter/rake/test_unit'
8
+
9
+ namespace :ci do
10
+ task :setup_rspec => "ci:setup:rspec"
11
+ task :setup_testunit => "ci:setup:testunit"
12
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: ci_reporter
5
+ version: !ruby/object:Gem::Version
6
+ version: "1.0"
7
+ date: 2007-02-14 00:00:00 -06:00
8
+ summary: CI::Reporter allows you to generate reams of XML for use with continuous integration systems.
9
+ require_paths:
10
+ - lib
11
+ email: nick@nicksieger.com
12
+ homepage: http://caldersphere.rubyforge.org/ci_reporter
13
+ rubyforge_project: caldersphere
14
+ description: CI::Reporter is an add-on to Test::Unit and RSpec that allows you to generate XML reports of your test and/or spec 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.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Nick Sieger
31
+ files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - Rakefile
36
+ - lib/ci/reporter/core.rb
37
+ - lib/ci/reporter/report_manager.rb
38
+ - lib/ci/reporter/rspec.rb
39
+ - lib/ci/reporter/test_suite.rb
40
+ - lib/ci/reporter/test_unit.rb
41
+ - lib/ci/reporter/rake/rspec.rb
42
+ - lib/ci/reporter/rake/rspec_loader.rb
43
+ - lib/ci/reporter/rake/test_unit.rb
44
+ - lib/ci/reporter/rake/test_unit_loader.rb
45
+ - spec/spec_helper.rb
46
+ - spec/ci/reporter/report_manager_spec.rb
47
+ - spec/ci/reporter/rspec_spec.rb
48
+ - spec/ci/reporter/test_suite_spec.rb
49
+ - spec/ci/reporter/test_unit_spec.rb
50
+ - tasks/ci_reporter.rake
51
+ test_files:
52
+ - spec/ci/reporter/report_manager_spec.rb
53
+ - spec/ci/reporter/rspec_spec.rb
54
+ - spec/ci/reporter/test_suite_spec.rb
55
+ - spec/ci/reporter/test_unit_spec.rb
56
+ rdoc_options: []
57
+
58
+ extra_rdoc_files: []
59
+
60
+ executables: []
61
+
62
+ extensions: []
63
+
64
+ requirements: []
65
+
66
+ dependencies: []
67
+