buildr 1.1.3 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|