Permalink
Browse files

- Prepare for 1.0 release; last set of changes in current svn location

git-svn-id: http://svn.caldersphere.net/svn/main/ci_reporter@64 b03c2d0b-2f10-0410-a2f9-fc8001506dfa
  • Loading branch information...
1 parent 9c52870 commit bfdcd216ecdcd684ae3f25ee0fca12ecbdec044b @nicksieger nicksieger committed Feb 15, 2007
View
@@ -0,0 +1,3 @@
+== 1.0
+
+Initial Release.
View
@@ -0,0 +1,41 @@
+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.
+
+== Installation
+
+CI::Reporter is available as a gem. To install the gem, use the usual gem command:
+
+ gem install ci_reporter
+
+To use CI::Reporter as a Rails plugin, first install the gem, and then install the plugin as follows:
+
+ script/plugin install http://svn.caldersphere.net/svn/main/plugins/ci_reporter
+
+== Usage
+
+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.
+
+1. To use CI::Reporter, simply add the following lines to your Rakefile:
+
+ require 'rubygems'
+ gem 'ci_reporter'
+ require 'ci/reporter/rake/rspec' # use this if you're using RSpec
+ require 'ci/reporter/rake/test_unit' # use this if you're using Test::Unit
+
+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.
+
+ rake ci:setup:testunit test
+
+== Advanced Usage
+
+If for some reason you can't use the above technique to inject CI::Reporter, you'll have to do one of these:
+
+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.
+2. If you're using +RSpec+, you'll need to pass the following arguments to the +spec+ command:
+ --require GEM_PATH/lib/ci/reporter/rake/rspec_loader
+ --format CI::Reporter::RSpec
+
+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.
View
@@ -1,7 +1,34 @@
require 'spec/rake/spectask'
+require 'hoe'
+
+MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt", "Rakefile",
+ "lib/**/*.rb", "spec/**/*.rb", "tasks/**/*.rake"]
+
+Hoe.new("ci_reporter", "1.0") do |p|
+ p.rubyforge_name = "caldersphere"
+ p.url = "http://rubyforge.org/projects/caldersphere"
+ p.author = "Nick Sieger"
+ p.email = "nick@nicksieger.com"
+ p.summary = "CI::Reporter allows you to generate reams of XML for use with continuous integration systems."
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
+ p.description = p.paragraphs_of('README.txt', 0..1).join("\n\n")
+ p.extra_deps.reject!{|d| d.first == "hoe"}
+ p.test_globs = ["spec/**/*_spec.rb"]
+end.spec.files = MANIFEST
+
+# Hoe insists on setting task :default => :test
+# !@#$ no easy way to empty the default list of prerequisites
+Rake::Task['default'].send :instance_variable_set, "@prerequisites", FileList[]
task :default => :spec
Spec::Rake::SpecTask.new do |t|
t.spec_opts = ["--diff", "unified"]
-end
+end
+
+# Automated manifest
+task :manifest do
+ File.open("Manifest.txt", "w") {|f| MANIFEST.each {|n| f << "#{n}\n"} }
+end
+
+task :package => :manifest
@@ -0,0 +1,9 @@
+namespace :ci do
+ namespace :setup do
+ task :rspec do
+ rm_rf ENV["CI_REPORTS"] || "spec/reports"
+ ENV["RSPECOPTS"] = ["--require", "#{File.dirname(__FILE__)}/rspec_loader.rb",
+ "--format", "CI::Reporter::RSpec"].join(" ")
+ end
+ end
+end
@@ -0,0 +1,7 @@
+require 'rubygems'
+begin
+ gem 'ci_reporter'
+rescue => e
+ $: << File.dirname(__FILE__) + "/../../../lib"
+end
+require 'ci/reporter/rspec'
@@ -0,0 +1,8 @@
+namespace :ci do
+ namespace :setup do
+ task :testunit do
+ rm_rf ENV["CI_REPORTS"] || "test/reports"
+ ENV["TESTOPTS"] = "#{File.dirname(__FILE__)}/test_unit_loader.rb"
+ end
+ end
+end
@@ -0,0 +1,22 @@
+require 'rubygems'
+begin
+ gem 'ci_reporter'
+rescue
+ $: << File.dirname(__FILE__) + "/../../../lib"
+end
+require 'ci/reporter/test_unit'
+
+module Test #:nodoc:all
+ module Unit
+ module UI
+ module Console
+ class TestRunner
+ def create_mediator(suite)
+ # swap in our custom mediator
+ return CI::Reporter::TestUnit.new(suite)
+ end
+ end
+ end
+ end
+ end
+end
@@ -1,7 +1,7 @@
require 'fileutils'
-module CI
- module Reporter
+module CI #:nodoc:
+ module Reporter #:nodoc:
class ReportManager
def initialize(prefix)
@basedir = ENV['CI_REPORTS'] || File.expand_path("#{Dir.getwd}/#{prefix.downcase}/reports")
View
@@ -4,6 +4,7 @@
module CI
module Reporter
+ # Wrapper around a <code>RSpec</code> error or failure to be used by the test suite to interpret results.
class RSpecFailure
def initialize(failure)
@failure = failure
@@ -22,6 +23,7 @@ def message() @failure.exception.message end
def location() @failure.exception.backtrace.join("\n") end
end
+ # Custom +RSpec+ formatter used to hook into the spec runs and capture results.
class RSpec < Spec::Runner::Formatter::ProgressBarFormatter
def initialize(output, dry_run=false, colour=false, report_mgr=nil)
super(output, dry_run, colour)
@@ -1,27 +1,32 @@
module CI
module Reporter
+ # Basic structure representing the running of a test suite. Used to time tests and store results.
class TestSuite < Struct.new(:name, :tests, :time, :failures, :errors)
attr_accessor :testcases
def initialize(name)
super
@testcases = []
end
+ # Starts timing the test suite.
def start
@start = Time.now
end
+ # Finishes timing the test suite.
def finish
self.tests = testcases.size
self.time = Time.now - @start
self.failures = testcases.select {|tc| tc.failure? }.size
self.errors = testcases.select {|tc| tc.error? }.size
end
+ # Creates the xml builder instance used to create the report xml document.
def create_builder
begin
+ gem 'builder'
require 'builder'
- rescue LoadError
+ rescue
begin
gem 'activesupport'
require 'active_support'
@@ -33,6 +38,7 @@ def create_builder
Builder::XmlMarkup.new(:indent => 2, :escape_attrs => true)
end
+ # Creates an xml string containing the test suite results.
def to_xml
builder = create_builder
# more recent version of Builder doesn't need the escaping
@@ -56,25 +62,31 @@ def builder.trunc!(txt)
end
end
+ # Structure used to represent an individual test case. Used to time the test and store the result.
class TestCase < Struct.new(:name, :time)
attr_accessor :failure
+ # Starts timing the test.
def start
@start = Time.now
end
+ # Finishes timing the test.
def finish
self.time = Time.now - @start
end
+ # Returns non-nil if the test failed.
def failure?
failure && failure.failure?
end
+ # Returns non-nil if the test had an error.
def error?
failure && failure.error?
end
+ # Writes xml representing the test result to the provided builder.
def to_xml(builder)
attrs = {}
each_pair {|k,v| attrs[k] = builder.trunc!(v.to_s) }
@@ -4,12 +4,15 @@
module CI
module Reporter
+ # Factory for constructing either a CI::Reporter::TestUnitFailure or CI::Reporter::TestUnitError depending on the result
+ # of the test.
class Failure
def self.new(fault)
fault.kind_of?(Test::Unit::Failure) ? TestUnitFailure.new(fault) : TestUnitError.new(fault)
end
end
+ # Wrapper around a <code>Test::Unit</code> error to be used by the test suite to interpret results.
class TestUnitError
def initialize(fault)
@fault = fault
@@ -21,6 +24,7 @@ def message() @fault.exception.message end
def location() @fault.exception.backtrace.join("\n") end
end
+ # Wrapper around a <code>Test::Unit</code> failure to be used by the test suite to interpret results.
class TestUnitFailure
def initialize(fault)
@fault = fault
@@ -32,6 +36,7 @@ def message() @fault.message end
def location() @fault.location.join("\n") end
end
+ # Replacement Mediator that adds listeners to capture the results of the <code>Test::Unit</code> runs.
class TestUnit < Test::Unit::UI::TestRunnerMediator
def initialize(suite, report_mgr = nil)
super(suite)
View
@@ -1,12 +1,12 @@
+begin
+ gem 'ci_reporter'
+rescue
+ $: << File.dirname(__FILE__) + "/../lib"
+end
+require 'ci/reporter/rake/rspec'
+require 'ci/reporter/rake/test_unit'
+
namespace :ci do
- task :setup_rspec do
- rm_rf ENV["CI_REPORTS"] || "spec/reports"
- ENV["RSPECOPTS"] = ["--require", "#{File.dirname(__FILE__)}/rspec_loader.rb",
- "--format", "CI::Reporter::RSpec"].join(" ")
- end
-
- task :setup_testunit do
- rm_rf ENV["CI_REPORTS"] || "test/reports"
- ENV["TESTOPTS"] = "#{File.dirname(__FILE__)}/test_unit_loader.rb"
- end
+ task :setup_rspec => "ci:setup:rspec"
+ task :setup_testunit => "ci:setup:testunit"
end
View
@@ -1,2 +0,0 @@
-$: << File.dirname(__FILE__) + "/../lib"
-require 'ci/reporter/rspec'
@@ -1,8 +0,0 @@
-$: << File.dirname(__FILE__) + "/../lib"
-require 'ci/reporter/test_unit'
-
-class Test::Unit::UI::Console::TestRunner
- def create_mediator(suite) # swap in our custom mediator
- return CI::Reporter::TestUnit.new(suite)
- end
-end

0 comments on commit bfdcd21

Please sign in to comment.