lib/java/test.rb in buildr-0.18.0 vs lib/java/test.rb in buildr-0.19.0
- old
+ new
@@ -1,175 +1,308 @@
+require "core/build"
+require "java/compile"
+
module Buildr
+ module Java
- class JUnitTask < Rake::Task
+ # The JUnit task executes JUnit test cases.
+ #
+ # The task requires one or more paths that contain the test cases (see #from),
+ # in addition to any classpath dependencies (see #with). From the test case
+ # directories it picks all classes that match the inclusion pattern and none
+ # that match the exclusion pattern and executes these in order. See #include
+ # for more information.
+ class JUnitTask < Rake::Task
- attr_accessor :classpath
+ attr_accessor :classpath
- def initialize(*args)
- super
- @classpath = []
- @paths = []
- @include = []
- @exclude = []
- enhance do |task|
- if test_cases.empty?
- puts "#{name}: No tests to run"
- else
- passed, failed = Java.junit(test_cases, :classpath=>classpath)
- fail "#{name}: The following tests failed:\n#{failed.join("\n")}" unless failed.empty?
+ def initialize(*args) #:nodoc:
+ super
+ @classpath = []
+ @paths = []
+ @include = []
+ @exclude = []
+ enhance do |task|
+ unless test_cases.empty?
+ puts "Running tests in #{name}" if verbose
+ passed, failed = Java.junit(test_cases, :classpath=>classpath + @paths)
+ fail "The following tests failed:\n#{failed.join("\n")}" unless failed.empty?
+ end
end
end
- end
- def from(*files)
- @paths += files
- self
- end
+ # :call-seq:
+ # include(*classes) => self
+ #
+ # Include only the specified test cases. Unless specified, the default is to include
+ # all test cases. This method accepts multiple arguments and returns self.
+ #
+ # Test cases are specified using the fully qualified class name. You can also use file-like
+ # patterns (glob) to specify collection of classes. For example:
+ # test.include "com.example.FirstTest"
+ # test.include "com.example.*"
+ # test.include "com.example.Module*"
+ # test.include "*.{First,Second}Test"
+ #
+ # If you do not specify any inclusion pattern explicitly, the default pattern is used.
+ # This pattern picks up all classes with a name ending with Test (same as test.include "*Test").
+ # Use the Test suffix to specify test case classes, and avoid the Test suffix for classes
+ # that do not implement test cases (e.g. mock objects, helpers, etc).
+ def include(*classes)
+ @include += classes
+ self
+ end
- def include(*files)
- @include += files
- self
- end
+ # :call-seq:
+ # exclude(*classes) => self
+ #
+ # Exclude the specified test cases. This method accepts multiple arguments and returns self.
+ # See #include for the type of arguments you can use.
+ def exclude(*classes)
+ @exclude += classes
+ self
+ end
- def exclude(*files)
- @exclude += files
- self
- end
+ # :call-seq:
+ # from(*paths) => self
+ #
+ # Specify one or more directories that include test cases.
+ def from(*files)
+ @paths += files
+ self
+ end
- def with(*files)
- @classpath |= artifacts(files.flatten).uniq
- self
- end
-
- def test_cases()
- unless @cases
- @include << "*" if @include.empty?
- @cases = @paths.map do |path|
- base = Pathname.new(path)
- FileList[File.join(path, "**", "*Test.class")].
- map { |file| Pathname.new(file).relative_path_from(base).to_s.ext("").gsub(File::SEPARATOR, ".") }.
- select { |name| @include.any? { |pattern| File.fnmatch(pattern, name) } }.
- reject { |name| @exclude.any? { |pattern| File.fnmatch(pattern, name) } }
- end.flatten.sort
+ # :call-seq:
+ # with(*specs) => self
+ #
+ # Specify artifacts (specs, tasks, files, etc) to include in the classpath when running
+ # the test cases.
+ def with(*files)
+ @classpath |= artifacts(files.flatten).uniq
+ self
end
- @cases
- end
- def invoke()
- setup
- begin
- super
- ensure
- teardown
+ private
+
+ def test_cases()
+ unless @cases
+ @include << "*Test" if @include.empty?
+ @cases = @paths.map do |path|
+ base = Pathname.new(path.to_s)
+ FileList["#{path}/**/*.class"].
+ map { |file| Pathname.new(file).relative_path_from(base).to_s.ext("").gsub(File::SEPARATOR, ".") }.
+ select { |name| @include.any? { |pattern| File.fnmatch(pattern, name) } }.
+ reject { |name| @exclude.any? { |pattern| File.fnmatch(pattern, name) } }
+ end.flatten.sort
+ end
+ @cases
end
- end
- def needed?()
- return true unless ENV["TESTS"] =~ /(no|off|false|disable)/i
end
- def prerequisites()
- super + classpath + @paths
- end
- def invoke_prerequisites()
- prerequisites.each { |n| application[n, @scope].invoke }
- end
+ # The test task controls the entire test lifecycle.
+ #
+ # You can use the test task in three ways. You can access and configure specific
+ # test tasks, e.g. enhance the #compile task, or run code during #setup/#teardown.
+ #
+ # You can use convenient methods that handle the most common settings. For example,
+ # add classpath dependencies using #with, or include only specific test cases
+ # using #include.
+ #
+ # You can also enhance this task directly. This task will first execute the #compile
+ # task, followed by the #setup task and #junit task, then any of your enhancements,
+ # and end by executing #teardown.
+ class TestTask < Rake::Task
- def setup()
- Rake::Task[name.sub(/run$/, "setup")].invoke
- end
-
- def teardown()
- Rake::Task[name.sub(/run$/, "teardown")].invoke
- end
+ def initialize(*args) #:nodoc:
+ super
+ enhance do
+ compile.invoke
+ setup.invoke
+ junit.invoke
+ enhance { teardown.invoke }
+ end
+ end
- end
+ # :call-seq:
+ # prepare(*prereqs) => task
+ # prepare(*prereqs) { |task| .. } => task
+ #
+ # Executes before the #compile task to prepare any source files used during compilation.
+ def prepare(*prereqs, &block)
+ @project.task("test:prepare").enhance prereqs, &block
+ end
+ # :call-seq:
+ # compile(*sources) => CompileTask
+ # compile(*sources) { |task| .. } => CompileTask
+ #
+ # The compile task is similar to the Project's compile task. However, it compiles all
+ # files found in the src/java/test directory into the target/test-classes directory.
+ # This task is executed by the test task before running any test cases.
+ #
+ # Once the project definition is complete, all classpath dependencies from the regular
+ # compile task are copied over, so you only need to specify classpath dependencies
+ # specific to your test cases. You can do so by calling #with on the test task.
+ # The classpath dependencies used here are also copied over to the junit task.
+ def compile(*sources, &block)
+ @project.task("test:compile").from(sources).enhance &block
+ end
+
+ # :call-seq:
+ # resources(*prereqs) => ResourcesTask
+ # resources(*prereqs) { |task| .. } => ResourcesTask
+ #
+ # Executes by the #compile task to copy resource files over. See Project#resources.
+ def resources(*prereqs, &block)
+ @project.task("test:resources").enhance prereqs, &block
+ end
- class Tests
+ # :call-seq:
+ # junit() => JUnitTask
+ #
+ # Returns the JUnit task. This task executes JUnit test cases, from classes compiled by
+ # the test task.
+ #
+ # By default it includes all classes with the suffix Test, and excludes all other classes.
+ # Use the Test suffix for classes that implement test cases, avoid this suffix for other
+ # classes (e.g. mocks, helper objects).
+ #
+ # You can also include only specific test cases, or exclude otherwise included test cases
+ # using #include and #exclude.
+ def junit()
+ @project.task("test:junit")
+ end
- def initialize(project)
- @project = project
- end
+ # :call-seq:
+ # setup(*prereqs) => task
+ # setup(*prereqs) { |task| .. } => task
+ #
+ # Returns the setup task. The setup task is executed at the beginning of the test task,
+ # after compiling the test files.
+ def setup(*prereqs, &block)
+ @project.task("test:setup").enhance prereqs, &block
+ end
- def prepare(*tasks, &block)
- @project.task("tests:prepare").enhance tasks, &block
- end
+ # :call-seq:
+ # teardown(*prereqs) => task
+ # teardown(*prereqs) { |task| .. } => task
+ #
+ # Returns the teardown task. The teardown task is executed at the end of the test task.
+ def teardown(*prereqs, &block)
+ @project.task("test.teardown").enhance prereqs, &block
+ end
- def compile(*sources, &block)
- @project.task("tests:compile").from(sources).enhance &block
- end
-
- def resources(*tasks, &block)
- @project.task("tests:resources").enhance tasks, &block
- end
+ # :call-seq:
+ # with(*specs) => self
+ #
+ # Specify artifacts (specs, tasks, files, etc) to include in the classpath when compiling
+ # and running test cases. Unless you need to limit specific classpath dependencies, use
+ # this instead of calling test.compile and test.junit individually.
+ def with(*artifacts)
+ compile.with artifacts
+ junit.with artifacts
+ self
+ end
- def setup(*tasks, &block)
- @project.task("tests:setup").enhance tasks, &block
- end
+ # :call-seq:
+ # include(*classes) => self
+ #
+ # See JUnitTask#include.
+ def include(*classes)
+ junit.include *classes
+ self
+ end
- def run(*tasks, &block)
- @project.task("tests:run").enhance tasks, &block
- end
+ # :call-seq:
+ # exclude(*classes) => self
+ #
+ # See JUnitTask#exclude.
+ def exclude(*classes)
+ junit.exclude *classes
+ self
+ end
- def teardown(*tasks, &block)
- @project.task("tests:teardown").enhance tasks, &block
end
end
class Project
- inherited_attr :test_src_dir do File.join(src_dir, "test", "java") end
- inherited_attr :test_resources_dir do File.join(src_dir, "test", "resources") end
- inherited_attr :test_target_dir do File.join(target_dir, "test-classes") end
- def tests()
- @tests ||= Tests.new(self)
+ # :call-seq:
+ # test(*prereqs) => TestTask
+ # test(*prereqs) { |task| .. } => TestTask
+ #
+ # Returns the test task. The test task controls the entire test lifecycle.
+ #
+ # You can use the test task in three ways. You can access and configure specific
+ # test tasks, e.g. enhance the compile task by calling test.compile, setup for
+ # the test cases by enhancing test.setup and so forth.
+ #
+ # You can use convenient methods that handle the most common settings. For example,
+ # add classpath dependencies using test.with, or include only specific test cases
+ # using test.include.
+ #
+ # You can also enhance this task directly. This method accepts a list of arguments
+ # that are used as prerequisites and an optional block that will be executed by the
+ # test task.
+ #
+ # This task will first execute the test.compile task, followed by the test.setup
+ # task and test.junit task, then any of your enhancements, and end by executing
+ # test.teardown.
+ def test(*prereqs, &block)
+ task("test").enhance prereqs, &block
end
-
- def test(*tasks, &block)
- tests.run *tasks, &block
- end
+
end
# Global task compiles all projects.
desc "Run all test cases"
- Project.local_task task("test")
+ Project.local_task("test") { |name| "Running tests in #{name}" }
Project.on_define do |project|
- namespace "tests" do
- # Compile task requires prepare and performs resources, if anything compiled.
- #Java::CompileTask.define_task("compile"=>[project.compile, task("prepare")]) { |task| project.tests.resources.invoke }
- Java::CompileTask.define_task("compile"=>[project.compile, task("prepare")]) { |task| project.tests.resources.invoke }
- # Resources task is a filter.
- FilterTask.define_task("resources")
- JUnitTask.define_task("run"=>task("compile"))
- task("setup")
- task("teardown")
- end
- project.tests.compile.with Java::JUNIT_REQUIRES
- project.recursive_task("test"=>project.test)
+ # Define a recursive test task, and pass it a reference to the project so it can discover all other tasks.
+ Java::TestTask.define_task("test")
+ project.test.instance_eval { instance_variable_set :@project, project }
+ project.recursive_task("test")
+ # Similar to the regular resources task but using different paths.
+ resources = Java::ResourcesTask.define_task("test:resources")
+ project.path_to("src/test/resources").tap { |dir| resources.filter.include project.path_to(dir, "*") if File.exist?(dir) }
+ # Similar to the regular compile task but using different paths.
+ compile = Java::CompileTask.define_task("test:compile"=>[project.compile, project.test.prepare, project.test.resources])
+ compile.enhance { project.test.resources.invoke }
+ project.path_to("src/test/java").tap { |dir| compile.from dir if File.exist?(dir) }
+ compile.into project.path_to("target/test-classes")
+ resources.filter.into compile.target
+ # Define the JUnit task here, otherwise we get a normal task.
+ Java::JUnitTask.define_task("test:junit")
+ # Define these tasks once, otherwise we may get a namespace error.
+ project.test.setup ; project.test.teardown
+ # Include the JUnit, Mock and other commonly used dependencies.
+ project.test.with Java::JUNIT_REQUIRES
project.enhance do |project|
- project.tests.compile.from project.path_to(:test_src_dir) if File.exist?(project.path_to(:test_src_dir))
- project.tests.compile.into project.path_to(:test_target_dir) unless project.tests.compile.target
- project.tests.resources.include project.path_to(:test_resources_dir, "*") if File.exists?(project.path_to(:test_resources_dir))
- project.tests.resources.into project.tests.compile.target unless project.tests.resources.target
-
- project.tests.compile.classpath += project.compile.classpath
- project.tests.compile.classpath << project.compile.target
- project.tests.run.from project.tests.compile.target
- project.tests.run.classpath += project.tests.compile.classpath
- project.tests.run.classpath << project.tests.compile.target
+ # Copy the regular compile classpath over, and also include the generated classes.
+ project.test.with project.compile.classpath, project.compile.target
+ project.test.junit.with project.test.compile.classpath
+ # Tell the JUnit task where to pick the test cases from.
+ project.test.junit.from project.test.compile.target
end
-
end
+ # This rule takes a suffix and runs that test case in the current project. For example;
+ # rake test:MyTest
+ # will run the test case class com.example.MyTest, if found in the current project.
rule /^test:.*$/ do |task|
test = task.name.scan(/test:(.*)/)[0][0]
Project.projects.select { |project| project.base_dir == Rake.application.original_dir }.
- map { |project| project.task("tests:run") }.
- each { |task| task.include("*#{test}").invoke }
+ map { |project| project.test }.each { |task| task.include("*#{test}").invoke }
end
+
+ # Require tests after build unless TEST option is off.
+ # For example:
+ # rake build
+ # rake build TEST=off
+ task("build") { task("test").invoke } unless ENV["TEST"] =~ /(off|false|no)/
end