buildr 1.1.3 → 1.2.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.
- data/CHANGELOG +48 -0
- data/README +1 -1
- data/Rakefile +204 -0
- data/bin/buildr +7 -0
- data/lib/buildr.rb +155 -16
- data/lib/buildr/cobertura.rb +26 -19
- data/lib/buildr/hibernate.rb +8 -6
- data/lib/buildr/javacc.rb +1 -0
- data/lib/buildr/jdepend.rb +31 -4
- data/lib/buildr/jetty.rb +26 -28
- data/lib/buildr/openjpa.rb +8 -6
- data/lib/buildr/xmlbeans.rb +9 -4
- data/lib/core/build.rb +40 -50
- data/lib/core/checks.rb +358 -0
- data/lib/core/common.rb +161 -62
- data/lib/core/generate.rb +65 -0
- data/lib/core/help.rb +72 -0
- data/lib/core/project.rb +32 -37
- data/lib/core/rake_ext.rb +12 -66
- data/lib/core/transports.rb +388 -363
- data/lib/java/ant.rb +33 -36
- data/lib/java/artifact.rb +172 -160
- data/lib/java/compile.rb +13 -21
- data/lib/java/eclipse.rb +5 -5
- data/lib/java/idea.ipr.template +284 -0
- data/lib/java/idea.rb +107 -72
- data/lib/java/java.rb +42 -18
- data/lib/java/packaging.rb +242 -124
- data/lib/java/test.rb +532 -135
- data/lib/tasks/zip.rb +72 -23
- metadata +24 -10
data/lib/java/test.rb
CHANGED
@@ -1,34 +1,22 @@
|
|
1
1
|
require "core/build"
|
2
2
|
require "java/compile"
|
3
|
+
require "java/ant"
|
4
|
+
require "core/help"
|
5
|
+
|
3
6
|
|
4
7
|
module Buildr
|
5
8
|
module Java
|
6
9
|
|
7
|
-
#
|
8
|
-
|
9
|
-
# The task requires one or more paths that contain the test cases (see #from),
|
10
|
-
# in addition to any classpath dependencies (see #with). From the test case
|
11
|
-
# directories it picks all classes that match the inclusion pattern and none
|
12
|
-
# that match the exclusion pattern and executes these in order. See #include
|
13
|
-
# for more information.
|
14
|
-
class JUnitTask < Rake::Task
|
10
|
+
# *Deprecated:* Use the test task directly instead of calling test.junit.
|
11
|
+
class JUnitTask < Rake::Task #:nodoc:
|
15
12
|
|
13
|
+
# The classpath used for running the tests. Includes the compile classpath,
|
14
|
+
# compiled classes (target). For everything else, add by calling #with.
|
16
15
|
attr_accessor :classpath
|
17
16
|
|
18
17
|
def initialize(*args) #:nodoc:
|
19
18
|
super
|
20
|
-
@
|
21
|
-
@paths = []
|
22
|
-
@include = ["*Test", "*Suite"]
|
23
|
-
@exclude = []
|
24
|
-
@options = {}
|
25
|
-
enhance do |task|
|
26
|
-
unless test_cases.empty?
|
27
|
-
puts "Running tests in #{name}" if verbose
|
28
|
-
passed, failed = Java.junit(test_cases, @options.merge(:classpath=>classpath + @paths))
|
29
|
-
fail "The following tests failed:\n#{failed.join("\n")}" unless failed.empty?
|
30
|
-
end
|
31
|
-
end
|
19
|
+
@parent = Rake::Task["#{name.split(":")[0...-1].join(":")}"]
|
32
20
|
end
|
33
21
|
|
34
22
|
# :call-seq:
|
@@ -48,7 +36,7 @@ module Buildr
|
|
48
36
|
# Use these suffixes for your test and test suite classes respectively, to distinguish them
|
49
37
|
# from stubs, helper classes, etc.
|
50
38
|
def include(*classes)
|
51
|
-
@include
|
39
|
+
@parent.include *classes
|
52
40
|
self
|
53
41
|
end
|
54
42
|
|
@@ -58,7 +46,7 @@ module Buildr
|
|
58
46
|
# Exclude the specified test cases. This method accepts multiple arguments and returns self.
|
59
47
|
# See #include for the type of arguments you can use.
|
60
48
|
def exclude(*classes)
|
61
|
-
@exclude
|
49
|
+
@parent.exclude *classes
|
62
50
|
self
|
63
51
|
end
|
64
52
|
|
@@ -67,7 +55,6 @@ module Buildr
|
|
67
55
|
#
|
68
56
|
# Specify one or more directories that include test cases.
|
69
57
|
def from(*files)
|
70
|
-
@paths += files
|
71
58
|
self
|
72
59
|
end
|
73
60
|
|
@@ -77,77 +64,121 @@ module Buildr
|
|
77
64
|
# Specify artifacts (specs, tasks, files, etc) to include in the classpath when running
|
78
65
|
# the test cases.
|
79
66
|
def with(*files)
|
80
|
-
@classpath
|
67
|
+
(@parent.options[:classpath] ||= []).concat files.flatten
|
81
68
|
self
|
82
69
|
end
|
83
70
|
|
84
71
|
# Returns the JUnit options.
|
85
|
-
|
72
|
+
def options()
|
73
|
+
@parent.options
|
74
|
+
end
|
86
75
|
|
87
76
|
# :call-seq:
|
88
77
|
# using(options) => self
|
89
78
|
#
|
90
|
-
# Sets the JUnit options from a hash and returns self. Right now supports passing properties to JUnit
|
79
|
+
# Sets the JUnit options from a hash and returns self. Right now supports passing :properties to JUnit,
|
80
|
+
# and :java_args to the JVM.
|
91
81
|
#
|
92
82
|
# For example:
|
93
83
|
# test.junit.using :properties=>{ "root"=>base_dir }
|
94
84
|
def using(options)
|
95
|
-
|
85
|
+
@parent.using options
|
96
86
|
self
|
97
87
|
end
|
98
88
|
|
99
|
-
private
|
100
|
-
|
101
|
-
def test_finding_pattern()
|
102
|
-
"*{Test,TestCase,Suite,TestSuite}"
|
103
|
-
end
|
104
|
-
|
105
|
-
def test_cases()
|
106
|
-
unless @cases
|
107
|
-
@cases = @paths.map do |path|
|
108
|
-
base = Pathname.new(path.to_s)
|
109
|
-
FileList["#{path}/**/#{test_finding_pattern}.class"].
|
110
|
-
map { |file| Pathname.new(file).relative_path_from(base).to_s.ext("").gsub(File::SEPARATOR, ".") }.
|
111
|
-
select { |name| @include.any? { |pattern| File.fnmatch(pattern, name) } }.
|
112
|
-
reject { |name| @exclude.any? { |pattern| File.fnmatch(pattern, name) } }
|
113
|
-
end.flatten.sort
|
114
|
-
end
|
115
|
-
@cases
|
116
|
-
end
|
117
|
-
|
118
89
|
end
|
119
90
|
|
120
91
|
|
121
92
|
# The test task controls the entire test lifecycle.
|
122
93
|
#
|
123
|
-
# You can use the test task in three ways. You can access and configure specific
|
124
|
-
#
|
94
|
+
# You can use the test task in three ways. You can access and configure specific test tasks,
|
95
|
+
# e.g. enhance the #compile task, or run code during #setup/#teardown.
|
125
96
|
#
|
126
|
-
# You can use convenient methods that handle the most common settings. For example,
|
127
|
-
#
|
128
|
-
#
|
97
|
+
# You can use convenient methods that handle the most common settings. For example, add classpath
|
98
|
+
# dependencies using #with, or include only specific test cases using #include.
|
99
|
+
#
|
100
|
+
# You can also enhance this task directly. This task will first execute the #compile task, followed
|
101
|
+
# by the #setup task, run the unit tests, any other enhancements, and end by executing #teardown.
|
129
102
|
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
103
|
+
# Unit tests are fun from classed compiled by the test.compile class that match the TEST_FILE_PATTERN
|
104
|
+
# (i.e. MyClassTest, MyClassTestSuite, etc). The test framework is determined by setting one of the
|
105
|
+
# test framework options to true, for example:
|
106
|
+
# test.unsing :testng
|
133
107
|
class TestTask < Rake::Task
|
134
108
|
|
109
|
+
class << self
|
110
|
+
|
111
|
+
# Used by the local test and integration tasks to
|
112
|
+
# a) Find the local project(s),
|
113
|
+
# b) Find all its sub-projects and narrow down to those that have either unit or integration tests,
|
114
|
+
# c) Run all the (either unit or integration) tests, and
|
115
|
+
# d) Ignore failure if necessary.
|
116
|
+
def run_local_tests(integration) #:nodoc:
|
117
|
+
Project.local_projects do |project|
|
118
|
+
# !(foo ^ bar) tests for equality and accepts nil as false (and select is less obfuscated than reject on ^).
|
119
|
+
projects = ([project] + project.projects).select { |project| !(project.test.options[:integration] ^ integration) }
|
120
|
+
projects.each do |project|
|
121
|
+
puts "Testing #{project.name}" if verbose
|
122
|
+
begin
|
123
|
+
project.test.invoke
|
124
|
+
rescue
|
125
|
+
raise unless Buildr.options.test == :all
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Used by the test/integration rule to only run tests that match the specified names.
|
132
|
+
def only_run(tests) #:nodoc:
|
133
|
+
tests = tests.map { |name| name =~ /\*/ ? name : "*#{name}*" }
|
134
|
+
# Since the test case may reside in a sub-project, we need to set the include/exclude pattern on
|
135
|
+
# all sub-projects, but only invoke test on the local project.
|
136
|
+
Project.projects.each { |project| project.test.instance_eval { @include = tests ; @exclude.clear } }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# List of supported test framework, first one being a default. Test frameworks are added by
|
141
|
+
# including them in TestTask (e.g. JUnit, TestNG).
|
142
|
+
TEST_FRAMEWORKS = []
|
143
|
+
|
144
|
+
# Default options already set on each test task.
|
145
|
+
DEFAULT_OPTIONS = { :fail_on_failure=>true }
|
146
|
+
|
147
|
+
# JMock version..
|
148
|
+
JMOCK_VERSION = "1.2.0"
|
149
|
+
# JMock specification.
|
150
|
+
JMOCK_REQUIRES = "jmock:jmock:jar:#{JMOCK_VERSION}"
|
151
|
+
|
152
|
+
# The classpath used for running the tests. Includes the compiled classes (compile.target) and
|
153
|
+
# their classpath dependencies. Will also include anything you pass to #with, shared between the
|
154
|
+
# testing compile and run classpath dependencies.
|
155
|
+
attr_reader :classpath
|
156
|
+
|
135
157
|
def initialize(*args) #:nodoc:
|
136
158
|
super
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
159
|
+
@classpath = []
|
160
|
+
@include = []
|
161
|
+
@exclude = []
|
162
|
+
parent = Rake::Task["^test"] if name[":"] # Only if in namespace
|
163
|
+
@options = parent && parent.respond_to?(:options) ? parent.options.clone : DEFAULT_OPTIONS.clone
|
164
|
+
enhance { run_tests }
|
165
|
+
end
|
166
|
+
|
167
|
+
def execute() #:nodoc:
|
168
|
+
setup.invoke
|
169
|
+
begin
|
170
|
+
super
|
171
|
+
@project.task("test:junit").invoke # In case someone enhanced it
|
172
|
+
rescue RuntimeError
|
173
|
+
raise if options[:fail_on_failure]
|
174
|
+
ensure
|
175
|
+
teardown.invoke
|
142
176
|
end
|
143
177
|
end
|
144
178
|
|
145
|
-
#
|
146
|
-
# prepare(*prereqs) => task
|
147
|
-
# prepare(*prereqs) { |task| .. } => task
|
148
|
-
#
|
149
|
-
# Executes before the #compile task to prepare any source files used during compilation.
|
179
|
+
# *Deprecated* Add a prerequisite to the compile task instead.
|
150
180
|
def prepare(*prereqs, &block)
|
181
|
+
warn_deprecated "Add a prerequisite to the compile task instead of using the prepare task."
|
151
182
|
@project.task("test:prepare").enhance prereqs, &block
|
152
183
|
end
|
153
184
|
|
@@ -176,22 +207,9 @@ module Buildr
|
|
176
207
|
@project.task("test:resources").enhance prereqs, &block
|
177
208
|
end
|
178
209
|
|
179
|
-
#
|
180
|
-
# junit() => JUnitTask
|
181
|
-
#
|
182
|
-
# Returns the JUnit task. This task executes JUnit test cases, from classes compiled by
|
183
|
-
# the test task.
|
184
|
-
#
|
185
|
-
# By default it includes all classes with the suffix Test or Suite, and excludes all other classes.
|
186
|
-
# Use the Test/Suite suffix for classes that implement test cases, avoid this suffix for other
|
187
|
-
# classes (e.g. stubs, helper objects).
|
188
|
-
#
|
189
|
-
# You can also include only specific test cases, or exclude otherwise included test cases
|
190
|
-
# using #include and #exclude.
|
191
|
-
#
|
192
|
-
# The Java property baseDir is set to the classes directory, you can use it to pick up test resources
|
193
|
-
# that you cannot access using getResources().
|
210
|
+
# *Deprecated* Use the test task directly instead of calling test.junit.
|
194
211
|
def junit()
|
212
|
+
warn_deprecated "Use the test task directly instead of calling test.junit."
|
195
213
|
@project.task("test:junit")
|
196
214
|
end
|
197
215
|
|
@@ -211,41 +229,323 @@ module Buildr
|
|
211
229
|
#
|
212
230
|
# Returns the teardown task. The teardown task is executed at the end of the test task.
|
213
231
|
def teardown(*prereqs, &block)
|
214
|
-
@project.task("test
|
232
|
+
@project.task("test:teardown").enhance prereqs, &block
|
215
233
|
end
|
216
234
|
|
217
235
|
# :call-seq:
|
218
236
|
# with(*specs) => self
|
219
237
|
#
|
220
238
|
# Specify artifacts (specs, tasks, files, etc) to include in the classpath when compiling
|
221
|
-
# and running test cases.
|
222
|
-
# this instead of calling test.compile and test.junit individually.
|
239
|
+
# and running test cases.
|
223
240
|
def with(*artifacts)
|
241
|
+
@classpath |= Buildr.artifacts(artifacts.flatten).uniq
|
224
242
|
compile.with artifacts
|
225
|
-
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns various test options.
|
247
|
+
attr_reader :options
|
248
|
+
|
249
|
+
# :call-seq:
|
250
|
+
# using(options) => self
|
251
|
+
#
|
252
|
+
# Sets various test options and returns self. Accepts a hash of options, or symbols (a symbol sets that
|
253
|
+
# option to true). For example:
|
254
|
+
# test.using :testng, :properties=>{ "url"=>"http://localhost:8080" }
|
255
|
+
#
|
256
|
+
# Currently supports the following options:
|
257
|
+
# * :properties -- System properties.
|
258
|
+
# * :java_args -- Java arguments when forking a new JVM.
|
259
|
+
# * :fail_on_failure -- True to fail on test failure (default is true).
|
260
|
+
def using(*args)
|
261
|
+
args.pop.each { |key, value| @options[key.to_sym] = value } if Hash === args.last
|
262
|
+
args.each { |key| @options[key.to_sym] = true }
|
226
263
|
self
|
227
264
|
end
|
228
265
|
|
229
266
|
# :call-seq:
|
230
267
|
# include(*classes) => self
|
231
268
|
#
|
232
|
-
#
|
269
|
+
# Include only the specified test cases. Unless specified, the default is to include
|
270
|
+
# all test cases. This method accepts multiple arguments and returns self.
|
271
|
+
#
|
272
|
+
# Test cases are specified using the fully qualified class name. You can also use file-like
|
273
|
+
# patterns (glob) to specify collection of classes. For example:
|
274
|
+
# test.include "com.example.FirstTest"
|
275
|
+
# test.include "com.example.*"
|
276
|
+
# test.include "com.example.Module*"
|
277
|
+
# test.include "*.{First,Second}Test"
|
278
|
+
#
|
279
|
+
# By default, all classes that have a name ending with Test or Suite are included.
|
280
|
+
# Use these suffixes for your test and test suite classes respectively, to distinguish them
|
281
|
+
# from stubs, helper classes, etc.
|
233
282
|
def include(*classes)
|
234
|
-
|
283
|
+
@include += classes
|
235
284
|
self
|
236
285
|
end
|
237
286
|
|
238
287
|
# :call-seq:
|
239
288
|
# exclude(*classes) => self
|
240
289
|
#
|
241
|
-
#
|
290
|
+
# Exclude the specified test cases. This method accepts multiple arguments and returns self.
|
291
|
+
# See #include for the type of arguments you can use.
|
242
292
|
def exclude(*classes)
|
243
|
-
|
293
|
+
@exclude += classes
|
244
294
|
self
|
245
295
|
end
|
246
296
|
|
297
|
+
# :call-seq:
|
298
|
+
# classes() => strings
|
299
|
+
#
|
300
|
+
# List of test classes to run. Determined by finding all the test classes in the target directory,
|
301
|
+
# and reducing based on the include/exclude patterns.
|
302
|
+
def classes()
|
303
|
+
base = Pathname.new(compile.target.to_s)
|
304
|
+
patterns = self.class.const_get("#{framework.to_s.upcase}_TESTS_PATTERN").to_a
|
305
|
+
FileList[patterns.map { |pattern| "#{base}/**/#{pattern}.class" }].
|
306
|
+
map { |file| Pathname.new(file).relative_path_from(base).to_s.ext("").gsub(File::SEPARATOR, ".") }.
|
307
|
+
select { |name| include?(name) }.flatten.sort
|
308
|
+
end
|
309
|
+
|
310
|
+
# List of failed test classes. Set after running the tests.
|
311
|
+
attr_reader :failed_tests
|
312
|
+
|
313
|
+
# :call-seq:
|
314
|
+
# include?(name) => boolean
|
315
|
+
#
|
316
|
+
# Returns true if the specified class name matches the inclusion/exclusion pattern. Used to determine
|
317
|
+
# which tests to execute.
|
318
|
+
def include?(name)
|
319
|
+
(@include.empty? || @include.any? { |pattern| File.fnmatch(pattern, name) }) &&
|
320
|
+
!@exclude.any? { |pattern| File.fnmatch(pattern, name) }
|
321
|
+
end
|
322
|
+
|
323
|
+
# :call-seq:
|
324
|
+
# requires() => classpath
|
325
|
+
#
|
326
|
+
# Returns the classpath for the selected test frameworks. Necessary for compiling and running test cases.
|
327
|
+
def requires()
|
328
|
+
self.class.const_get("#{framework.to_s.upcase}_REQUIRES").to_a + [JMOCK_REQUIRES]
|
329
|
+
end
|
330
|
+
|
331
|
+
# :call-seq:
|
332
|
+
# framework() => symbol
|
333
|
+
#
|
334
|
+
# Returns the test framework, e.g. :junit, :testng.
|
335
|
+
def framework()
|
336
|
+
@framework ||= TEST_FRAMEWORKS.detect { |name| options[name] } || TEST_FRAMEWORKS.first
|
337
|
+
end
|
338
|
+
|
339
|
+
# :call-seq:
|
340
|
+
# report_to() => file
|
341
|
+
#
|
342
|
+
# Test frameworks that can produce reports, will write them to this directory.
|
343
|
+
#
|
344
|
+
# This is framework dependent, so unless you use the default test framework, call this method
|
345
|
+
# after setting the test framework.
|
346
|
+
def report_to()
|
347
|
+
@report_to ||= file(@project.path_to(:reports, "#{framework}")=>self)
|
348
|
+
end
|
349
|
+
|
350
|
+
protected
|
351
|
+
|
352
|
+
# :call-seq:
|
353
|
+
# run_tests()
|
354
|
+
#
|
355
|
+
# Runs the test cases using the selected test framework. Executes as part of the task.
|
356
|
+
def run_tests()
|
357
|
+
classes = self.classes
|
358
|
+
if classes.empty?
|
359
|
+
@failed_tests = []
|
360
|
+
else
|
361
|
+
puts "Running tests in #{@project.name}" if verbose
|
362
|
+
@failed_tests = send("#{framework}_run",
|
363
|
+
:classes => classes,
|
364
|
+
:classpath => @classpath + [compile.target],
|
365
|
+
:properties => { "baseDir" => compile.target.to_s }.merge(options[:properties] || {}),
|
366
|
+
:java_args => options[:java_args])
|
367
|
+
unless @failed_tests.empty?
|
368
|
+
warn "The following tests failed:\n#{@failed_tests.join("\n")}" if verbose
|
369
|
+
fail "Tests failed!"
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
247
374
|
end
|
248
375
|
|
376
|
+
|
377
|
+
# The JUnit test framework. This is the default test framework, but you can force it by
|
378
|
+
# adding the following to your project:
|
379
|
+
# test.using :testng
|
380
|
+
#
|
381
|
+
# You can use the report method to control the junit:report task.
|
382
|
+
module JUnit
|
383
|
+
|
384
|
+
# Used by the junit:report task. Access through JUnit#report if you want to set various
|
385
|
+
# options for that task, for example:
|
386
|
+
# JUnit.report.frames = false
|
387
|
+
class Report
|
388
|
+
|
389
|
+
# Ant-Trax required for running the JUnitReport task.
|
390
|
+
Java.rjb.onload { |rjb| rjb.classpath << "org.apache.ant:ant-trax:jar:#{Ant::VERSION}" }
|
391
|
+
|
392
|
+
# Parameters passed to the Ant JUnitReport task.
|
393
|
+
attr_reader :params
|
394
|
+
# True (default) to produce a report using frames, false to produce a single-page report.
|
395
|
+
attr_accessor :frames
|
396
|
+
# Directory for the report style (defaults to using the internal style).
|
397
|
+
attr_accessor :style_dir
|
398
|
+
# Target directory for generated report.
|
399
|
+
attr_accessor :target
|
400
|
+
|
401
|
+
def initialize()
|
402
|
+
@params = {}
|
403
|
+
@frames = true
|
404
|
+
@target = "reports/junit"
|
405
|
+
end
|
406
|
+
|
407
|
+
# :call-seq:
|
408
|
+
# generate(projects, target?)
|
409
|
+
#
|
410
|
+
# Generates a JUnit report for these projects (must run JUnit tests first) into the
|
411
|
+
# target directory. You can specify a target, or let it pick the default one from the
|
412
|
+
# target attribute.
|
413
|
+
def generate(projects, target = @target.to_s)
|
414
|
+
html_in = File.join(target, "html")
|
415
|
+
rm_rf html_in ; mkpath html_in
|
416
|
+
|
417
|
+
Buildr.ant("junit-report") do |ant|
|
418
|
+
ant.junitreport :todir=>target do
|
419
|
+
projects.select { |project| project.test.framework == :junit }.
|
420
|
+
map { |project| project.test.report_to.to_s }.select { |path| File.exist?(path) }.
|
421
|
+
each { |path| ant.fileset(:dir=>path) { ant.include :name=>"TEST-*.xml" } }
|
422
|
+
options = { :format=>frames ? "frames" : "noframes" }
|
423
|
+
options[:styledir] = style_dir if style_dir
|
424
|
+
ant.report options.merge(:todir=>html_in) do
|
425
|
+
params.each { |key, value| ant.param :name=>key, :expression=>value }
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
end
|
432
|
+
|
433
|
+
# JUnit version number.
|
434
|
+
JUNIT_VERSION = "4.3.1"
|
435
|
+
# JUnit specification.
|
436
|
+
JUNIT_REQUIRES = "junit:junit:jar:#{JUNIT_VERSION}"
|
437
|
+
# Pattern for selecting JUnit test classes. Regardless of include/exclude patterns, only classes
|
438
|
+
# that match this pattern are used.
|
439
|
+
JUNIT_TESTS_PATTERN = [ "Test*", "*Test" ]
|
440
|
+
|
441
|
+
# Ant-JUnit requires for JUnit and JUnit reports tasks.
|
442
|
+
Java.rjb.onload { |rjb| rjb.classpath << "org.apache.ant:ant-junit:jar:#{Ant::VERSION}" }
|
443
|
+
|
444
|
+
class << self
|
445
|
+
|
446
|
+
# :call-seq:
|
447
|
+
# report()
|
448
|
+
#
|
449
|
+
# Returns the Report object used by the junit:report task. You can use this object to set
|
450
|
+
# various options that affect your report, for example:
|
451
|
+
# JUnit.report.frames = false
|
452
|
+
# JUnit.report.params["title"] = "My App"
|
453
|
+
def report()
|
454
|
+
@report ||= Report.new
|
455
|
+
end
|
456
|
+
|
457
|
+
def included(mod)
|
458
|
+
mod::TEST_FRAMEWORKS << :junit
|
459
|
+
end
|
460
|
+
private :included
|
461
|
+
|
462
|
+
end
|
463
|
+
|
464
|
+
private
|
465
|
+
|
466
|
+
def junit_run(args)
|
467
|
+
rm_rf report_to.to_s ; mkpath report_to.to_s
|
468
|
+
# Use Ant to execute the Junit tasks, gives us performance and reporting.
|
469
|
+
Buildr.ant("junit") do |ant|
|
470
|
+
ant.junit :printsummary=>"withOutAndErr" do
|
471
|
+
ant.classpath :path=>args[:classpath].map(&:to_s).each { |path| file(path).invoke }.join(File::PATH_SEPARATOR)
|
472
|
+
args[:properties].each { |key, value| ant.sysproperty :key=>key, :value=>value }
|
473
|
+
ant.formatter :type=>"plain"
|
474
|
+
ant.formatter :type=>"xml"
|
475
|
+
ant.batchtest :todir=>report_to.to_s, :failureproperty=>"failed" do
|
476
|
+
ant.fileset :dir=>compile.target.to_s do
|
477
|
+
args[:classes].each { |cls| ant.include :name=>cls.gsub(".", "/").ext("class") }
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
return [] unless ant.project.getProperty("failed")
|
482
|
+
end
|
483
|
+
# But Ant doesn't tell us what went kaput, so we'll have to parse the test files.
|
484
|
+
args[:classes].inject([]) do |failed, name|
|
485
|
+
if report = File.read(File.join(report_to.to_s, "TEST-#{name}.txt")) rescue nil
|
486
|
+
# The second line (if exists) is the status line and we scan it for its values.
|
487
|
+
status = (report.split("\n")[1] || "").scan(/(run|failures|errors):\s*(\d+)/i).
|
488
|
+
inject(Hash.new(0)) { |hash, pair| hash[pair[0].downcase.to_sym] = pair[1].to_i ; hash }
|
489
|
+
failed << name if status[:failures] > 0 || status[:errors] > 0
|
490
|
+
end
|
491
|
+
failed
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
namespace "junit" do
|
496
|
+
desc "Generate JUnit tests report in #{report.target}"
|
497
|
+
task("report") do |task|
|
498
|
+
report.generate Project.projects
|
499
|
+
puts "Generated JUnit tests report in #{report.target}"
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
task("clean") { rm_rf report.target.to_s }
|
504
|
+
|
505
|
+
end
|
506
|
+
|
507
|
+
|
508
|
+
# The TestNG test framework. Use by adding the following to your project:
|
509
|
+
# test.using :testng
|
510
|
+
module TestNG
|
511
|
+
|
512
|
+
# TestNG version number.
|
513
|
+
TESTNG_VERSION = "5.5"
|
514
|
+
# TestNG specification.
|
515
|
+
TESTNG_REQUIRES = "org.testng:testng:jar:jdk15:#{TESTNG_VERSION}"
|
516
|
+
# Pattern for selecting TestNG test classes. Regardless of include/exclude patterns, only classes
|
517
|
+
# that match this pattern are used.
|
518
|
+
TESTNG_TESTS_PATTERN = [ "Test*", "*Test", "*TestCase" ]
|
519
|
+
|
520
|
+
class << self
|
521
|
+
|
522
|
+
def included(mod)
|
523
|
+
mod::TEST_FRAMEWORKS << :testng
|
524
|
+
end
|
525
|
+
private :included
|
526
|
+
|
527
|
+
end
|
528
|
+
|
529
|
+
private
|
530
|
+
|
531
|
+
def testng_run(args)
|
532
|
+
cmd_args = [ "org.testng.TestNG", "-sourcedir", compile.sources.join(";"), "-suitename", @project.name ]
|
533
|
+
cmd_args << "-d" << report_to.to_s
|
534
|
+
cmd_options = args.only(:classpath, :properties, :java_args)
|
535
|
+
args[:classes].inject([]) do |failed, test|
|
536
|
+
begin
|
537
|
+
Buildr.java cmd_args, "-testclass", test, cmd_options.merge(:name=>test)
|
538
|
+
failed
|
539
|
+
rescue
|
540
|
+
failed << test
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
end
|
546
|
+
|
547
|
+
class TestTask ; include JUnit ; include TestNG ; end
|
548
|
+
|
249
549
|
end
|
250
550
|
|
251
551
|
|
@@ -269,71 +569,46 @@ module Buildr
|
|
269
569
|
# that are used as prerequisites and an optional block that will be executed by the
|
270
570
|
# test task.
|
271
571
|
#
|
272
|
-
# This task
|
273
|
-
#
|
274
|
-
#
|
572
|
+
# This task compiles the project and the test cases (in that order) before running any tests.
|
573
|
+
# It execute the setup task, runs all the test cases, any enhancements, and ends with the
|
574
|
+
# teardown tasks.
|
275
575
|
def test(*prereqs, &block)
|
276
576
|
task("test").enhance prereqs, &block
|
277
577
|
end
|
278
578
|
|
279
579
|
end
|
280
580
|
|
281
|
-
# Global task compiles all projects.
|
282
|
-
desc "Run all test cases"
|
283
|
-
Project.local_task("test") { |name| "Running tests in #{name}" }
|
284
581
|
|
285
582
|
Project.on_define do |project|
|
286
583
|
# Define a recursive test task, and pass it a reference to the project so it can discover all other tasks.
|
287
584
|
Java::TestTask.define_task("test")
|
288
585
|
project.test.instance_eval { instance_variable_set :@project, project }
|
289
|
-
project.recursive_task("test")
|
586
|
+
#project.recursive_task("test")
|
290
587
|
# Similar to the regular resources task but using different paths.
|
291
588
|
resources = Java::ResourcesTask.define_task("test:resources")
|
292
|
-
|
589
|
+
project.path_to("src/test/resources").tap { |dir| resources.filter.from dir if File.exist?(dir) }
|
293
590
|
# Similar to the regular compile task but using different paths.
|
294
|
-
compile = Java::CompileTask.define_task("test:compile"=>[project.compile,
|
591
|
+
compile = Java::CompileTask.define_task("test:compile"=>[project.compile, task("test:prepare"), project.test.resources])
|
295
592
|
project.path_to("src/test/java").tap { |dir| compile.from dir if File.exist?(dir) }
|
296
593
|
compile.into project.path_to(:target, "test-classes")
|
297
594
|
resources.filter.into compile.target
|
595
|
+
project.test.enhance [compile]
|
298
596
|
# Define the JUnit task here, otherwise we get a normal task.
|
299
597
|
Java::JUnitTask.define_task("test:junit")
|
300
598
|
# Define these tasks once, otherwise we may get a namespace error.
|
301
599
|
project.test.setup ; project.test.teardown
|
302
|
-
# Include the JUnit, Mock and other commonly used dependencies.
|
303
|
-
project.test.with Java::JUNIT_REQUIRES
|
304
600
|
|
305
601
|
project.enhance do |project|
|
306
|
-
# Copy the regular compile classpath over, and also include the generated classes
|
307
|
-
|
308
|
-
project.test.
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
end
|
316
|
-
project.clean { verbose(false) { rm_rf project.test.compile.target.to_s } }
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
# This rule takes a suffix and runs that test case in the current project. For example;
|
321
|
-
# rake test:MyTest
|
322
|
-
# will run the test case class com.example.MyTest, if found in the current project.
|
323
|
-
rule /^test:.*$/ do |task|
|
324
|
-
test = task.name.scan(/test:(.*)/)[0][0]
|
325
|
-
# Glob if no glob pattern used.
|
326
|
-
test = "*#{test}*" unless test =~ /\*/
|
327
|
-
if test =~ /\{.+\}/
|
328
|
-
# Unfortunately, fnmatch doesn't do {foo,bar}, so we have to expand those ourselves.
|
329
|
-
tests = test[/\{.+\}/][1...-1].split(",").map { |name| test.sub(/\{.+\}/, name) }
|
330
|
-
else
|
331
|
-
tests = [test]
|
602
|
+
# Copy the regular compile classpath over, and also include the generated classes, both of which
|
603
|
+
# can be used in the test cases. And don't forget the classpath required by the test framework (e.g. JUnit).
|
604
|
+
project.test.with project.compile.classpath, project.compile.target, project.test.requires
|
605
|
+
project.clean do
|
606
|
+
verbose(false) do
|
607
|
+
rm_rf project.test.compile.target.to_s
|
608
|
+
rm_rf project.test.report_to.to_s
|
609
|
+
end
|
610
|
+
end
|
332
611
|
end
|
333
|
-
# Since the test case may reside in a sub-project, we need to set the include/exclude pattern on
|
334
|
-
# all sub-projects, but only invoke test on the local project.
|
335
|
-
Project.projects.each { |project| project.test.junit.instance_eval { @include = tests ; @exclude.clear } }
|
336
|
-
Project.local_projects.each { |project| project.test.invoke }
|
337
612
|
end
|
338
613
|
|
339
614
|
|
@@ -342,22 +617,144 @@ module Buildr
|
|
342
617
|
# Runs test cases after the build when true (default). This forces test cases to execute
|
343
618
|
# after the build, including when running build related tasks like install, deploy and release.
|
344
619
|
#
|
345
|
-
#
|
346
|
-
#
|
347
|
-
#
|
348
|
-
#
|
620
|
+
# Set to false to not run any test cases. Set to :all to run all test cases, ignoring failures.
|
621
|
+
#
|
622
|
+
# This option is set from the environment variable "test", so you can also do:
|
623
|
+
# buildr # With tests
|
624
|
+
# buildr test=no # Without tests
|
625
|
+
# buildr test=all # Ignore failures
|
349
626
|
attr_accessor :test
|
350
627
|
|
628
|
+
def test() #:nodoc:
|
629
|
+
if @test.nil?
|
630
|
+
case value = ENV["TEST"] || ENV["test"]
|
631
|
+
when /^(no|off|false|skip)$/i
|
632
|
+
@test = false
|
633
|
+
when /^all$/i
|
634
|
+
@test = :all
|
635
|
+
when /^(yes|on|true)$/i, nil
|
636
|
+
@test = true
|
637
|
+
else
|
638
|
+
warn "Expecting the environment variable test to be 'no' or 'all', not sure what to do with #{value}, so I'm just going to run all the test cases and stop at failure."
|
639
|
+
@test = true
|
640
|
+
end
|
641
|
+
end
|
642
|
+
@test
|
643
|
+
end
|
644
|
+
|
351
645
|
end
|
352
646
|
|
353
|
-
options.test = (ENV["TEST"] || ENV["test"]) !~ /(no|off|false)/
|
354
647
|
|
355
|
-
|
648
|
+
desc "Run all test cases"
|
649
|
+
task("test") { TestTask.run_local_tests false }
|
650
|
+
|
651
|
+
# This rule takes a suffix and runs that test case in the current project. For example;
|
652
|
+
# buildr test:MyTest
|
653
|
+
# will run the test case class com.example.MyTest, if found in the current project.
|
654
|
+
#
|
655
|
+
# If you want to run multiple test cases, separate tham with a comma. You can also use glob
|
656
|
+
# (* and ?) patterns to match multiple tests, e.g. com.example.* to run all test cases in
|
657
|
+
# a given package. If you don't specify a glob pattern, asterisks are added for you.
|
658
|
+
rule /^test:.*$/ do |task|
|
659
|
+
TestTask.only_run task.name.scan(/test:(.*)/)[0][0].split(",")
|
660
|
+
task("test").invoke
|
661
|
+
end
|
662
|
+
|
663
|
+
task "build" do |task|
|
356
664
|
# Make sure this happens as the last action on the build, so all other enhancements
|
357
665
|
# are made to run before starting the test cases.
|
358
666
|
task.enhance do
|
359
|
-
task("test").invoke
|
667
|
+
task("test").invoke unless Buildr.options.test == false
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
|
672
|
+
# The integration tests task. Buildr has one such task (see Buildr#integration) that runs
|
673
|
+
# all tests marked with :integration=>true, and has a setup/teardown tasks separate from
|
674
|
+
# the unit tests.
|
675
|
+
class IntegrationTestsTask < Rake::Task
|
676
|
+
|
677
|
+
def initialize(*args) #:nodoc:
|
678
|
+
super
|
679
|
+
task "#{name}-setup"
|
680
|
+
task "#{name}-teardown"
|
681
|
+
enhance { puts "Running integration tests..." if verbose }
|
360
682
|
end
|
683
|
+
|
684
|
+
def execute() #:nodoc:
|
685
|
+
setup.invoke
|
686
|
+
begin
|
687
|
+
super
|
688
|
+
ensure
|
689
|
+
teardown.invoke
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
# :call-seq:
|
694
|
+
# setup(*prereqs) => task
|
695
|
+
# setup(*prereqs) { |task| .. } => task
|
696
|
+
#
|
697
|
+
# Returns the setup task. The setup task is executed before running the integration tests.
|
698
|
+
def setup(*prereqs, &block)
|
699
|
+
Rake::Task["rake:integration-setup"].enhance prereqs, &block
|
700
|
+
end
|
701
|
+
|
702
|
+
# :call-seq:
|
703
|
+
# teardown(*prereqs) => task
|
704
|
+
# teardown(*prereqs) { |task| .. } => task
|
705
|
+
#
|
706
|
+
# Returns the teardown task. The teardown task is executed after running the integration tests.
|
707
|
+
def teardown(*prereqs, &block)
|
708
|
+
Rake::Task["rake:integration-teardown"].enhance prereqs, &block
|
709
|
+
end
|
710
|
+
|
711
|
+
end
|
712
|
+
|
713
|
+
# :call-seq:
|
714
|
+
# integration() { |task| .... }
|
715
|
+
# integration() => IntegrationTestTask
|
716
|
+
#
|
717
|
+
# Use this method to return the integration tests task, or enhance it with a block to execute.
|
718
|
+
#
|
719
|
+
# There is one integration tests task you can execute directly, or as a result of running the package
|
720
|
+
# task (or tasks that depend on it, like install and deploy). It contains all the tests marked with
|
721
|
+
# :integration=>true, all other tests are considered unit tests and run by the test task before packaging.
|
722
|
+
# So essentially: build=>test=>packaging=>integration=>install/deploy.
|
723
|
+
#
|
724
|
+
# You add new test cases from projects that define integration tests using the regular test task,
|
725
|
+
# but with the following addition:
|
726
|
+
# test.using :integration
|
727
|
+
#
|
728
|
+
# Use this method to enhance the setup and teardown tasks that are executed before (and after) all
|
729
|
+
# integration tests are run, for example, to start a Web server or create a database.
|
730
|
+
def integration(*deps, &block)
|
731
|
+
Rake::Task["rake:integration"].enhance deps, &block
|
732
|
+
end
|
733
|
+
|
734
|
+
IntegrationTestsTask.define_task("integration") { TestTask.run_local_tests true }
|
735
|
+
|
736
|
+
# Similar to test:[pattern] but for integration tests.
|
737
|
+
rule /^integration:.*$/ do |task|
|
738
|
+
TestTask.only_run task.name.scan(/integration:(.*)/)[0][0].split(",")
|
739
|
+
task("integration").invoke
|
740
|
+
end
|
741
|
+
|
742
|
+
# Anything that comes after local packaging (install, deploy) executes the integration tests,
|
743
|
+
# which do not conflict with integration invoking the project's own packaging (package=>
|
744
|
+
# integration=>foo:package is not circular, just confusing to debug.)
|
745
|
+
task "package" do |task|
|
746
|
+
integration.invoke if Buildr.options.test && Rake.application.original_dir == Dir.pwd
|
747
|
+
end
|
748
|
+
|
749
|
+
|
750
|
+
task("help") do
|
751
|
+
puts
|
752
|
+
puts "To run a full build without running any test cases:"
|
753
|
+
puts " buildr test=no"
|
754
|
+
puts "To run specific test case:"
|
755
|
+
puts " buildr test:MyTest"
|
756
|
+
puts "To run integration tests:"
|
757
|
+
puts " buildr integration"
|
361
758
|
end
|
362
759
|
|
363
760
|
end
|