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